Merge branch 'stable-3.2'
* stable-3.2:
CreateChange: Clarify the e2e test access modifier
e2e-tests: Fix minor comma styling inconsistencies
Set version to 2.16.19
Set version to 3.2.0-SNAPSHOT
Change-Id: I2aa9688bc7dfbd46bf0a7364d67517c9ed8473bb
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index aa6e400..01cd494 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -21,7 +21,7 @@
* A JDK for Java 8|9|10|11|...
* Python 2 or 3
* link:https://github.com/nodesource/distributions/blob/master/README.md[Node.js (including npm),role=external,window=_blank]
-* Bower (`sudo npm install -g bower`)
+* Bower (`npm install -g bower`)
* link:https://docs.bazel.build/versions/master/install.html[Bazel,role=external,window=_blank] -launched with
link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank]
* Maven
@@ -32,12 +32,11 @@
[[bazel]]
=== Bazel
-link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank] includes a
-link:https://bazel.build/[Bazel,role=external,window=_blank] version check and downloads the correct
-`bazel` version for the git project/repository. Bazelisk is the recommended
-`bazel` launcher for Gerrit. Once Bazelisk is installed locally, a `bazel`
-symlink can be created towards it. This is so that every `bazel` command
-seamlessly uses Bazelisk, which then runs the proper `bazel` binary version.
+link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank] is a version
+manager for link:https://bazel.build/[Bazel,role=external,window=_blank], similar to how `nvm`
+manages `npm` versions. It takes care of downloading and installing Bazel itself, so you don't have
+to worry about using the correct version of Bazel. Bazelisk can be installed in different
+ways: link:https://docs.bazel.build/install-bazelisk.html[Install,role=external,window=_blank]
[[java]]
=== Java
diff --git a/Documentation/intro-gerrit-walkthrough.txt b/Documentation/intro-gerrit-walkthrough.txt
index 92732d0..6565ba4 100644
--- a/Documentation/intro-gerrit-walkthrough.txt
+++ b/Documentation/intro-gerrit-walkthrough.txt
@@ -296,6 +296,10 @@
* Review the link:intro-project-owner.html[Project Owners guide] to learn more
about configuring projects in Gerrit, including setting user permissions and
configuring verification checks
+* Read through the Git and Gerrit training slides that explain concepts and
+ workflows in detail. They are meant for self-studying how Git and Gerrit work:
+** link:https://docs.google.com/presentation/d/1IQCRPHEIX-qKo7QFxsD3V62yhyGA9_5YsYXFOiBpgkk/edit?usp=sharing[Git explained: Git Concepts and Workflows]
+** link:https://docs.google.com/presentation/d/1C73UgQdzZDw0gzpaEqIC6SPujZJhqamyqO1XOHjH-uk/edit?usp=sharing[Gerrit explained: Gerrit Concepts and Workflows]
GERRIT
------
diff --git a/Documentation/js_licenses.txt b/Documentation/js_licenses.txt
index bd26190..97c2548 100644
--- a/Documentation/js_licenses.txt
+++ b/Documentation/js_licenses.txt
@@ -778,39 +778,6 @@
----
-[[moment]]
-moment
-
-* moment
-
-[[moment_license]]
-----
-Copyright (c) JS Foundation and other contributors
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
[[font-roboto-local-fonts-roboto]]
font-roboto-local-fonts-roboto
diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt
index 63c569a..c1dfb94 100644
--- a/Documentation/licenses.txt
+++ b/Documentation/licenses.txt
@@ -3720,39 +3720,6 @@
----
-[[moment]]
-moment
-
-* moment
-
-[[moment_license]]
-----
-Copyright (c) JS Foundation and other contributors
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-----
-
-
[[font-roboto-local-fonts-roboto]]
font-roboto-local-fonts-roboto
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 0badced..4006d1d 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -5731,6 +5731,11 @@
The list of commits that are being integrated into the destination
branch by submitting the merge commit.
+* `/PATCHSET_LEVEL`:
++
+This file path is used exclusively for posting and indicating
+patchset-level comments, thus not relevant for other use-cases.
+
[[fix-id]]
=== \{fix-id\}
UUID of a suggested fix.
@@ -6226,7 +6231,7 @@
comments may be returned for multiple patch sets.
|`id` ||The URL encoded UUID of the comment.
|`path` |optional|
-The path of the file for which the inline comment was done. +
+link:#file-id[The file path] for which the inline comment was done. +
Not set if returned in a map where the key is the file path.
|`side` |optional|
The side on which the comment was added. +
@@ -6279,7 +6284,7 @@
The URL encoded UUID of the comment if an existing draft comment should
be updated.
|`path` |optional|
-The path of the file for which the inline comment should be added. +
+link:#file-id[The file path] for which the inline comment should be added. +
Doesn't need to be set if contained in a map where the key is the file
path.
|`side` |optional|
diff --git a/java/com/google/gerrit/entities/Patch.java b/java/com/google/gerrit/entities/Patch.java
index 50f86fe..3926d47 100644
--- a/java/com/google/gerrit/entities/Patch.java
+++ b/java/com/google/gerrit/entities/Patch.java
@@ -35,6 +35,12 @@
public static final String MERGE_LIST = "/MERGE_LIST";
/**
+ * Magical file name which doesn't represent a file. Used specifically for patchset-level
+ * comments.
+ */
+ public static final String PATCHSET_LEVEL = "/PATCHSET_LEVEL";
+
+ /**
* Checks if the given path represents a magic file. A magic file is a generated file that is
* automatically included into changes. It does not exist in the commit of the patch set.
*
@@ -42,7 +48,7 @@
* @return {@code true} if the path represents a magic file, otherwise {@code false}.
*/
public static boolean isMagic(String path) {
- return COMMIT_MSG.equals(path) || MERGE_LIST.equals(path);
+ return COMMIT_MSG.equals(path) || MERGE_LIST.equals(path) || PATCHSET_LEVEL.equals(path);
}
public static Key key(PatchSet.Id patchSetId, String fileName) {
diff --git a/java/com/google/gerrit/extensions/annotations/RemoveAfter.java b/java/com/google/gerrit/extensions/annotations/RemoveAfter.java
index aa31dd0..02f70e9 100644
--- a/java/com/google/gerrit/extensions/annotations/RemoveAfter.java
+++ b/java/com/google/gerrit/extensions/annotations/RemoveAfter.java
@@ -14,7 +14,7 @@
package com.google.gerrit.extensions.annotations;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.ElementType;
@@ -26,7 +26,7 @@
* period we promised to users.
*/
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
-@Retention(SOURCE)
+@Retention(RUNTIME)
@BindingAnnotation
public @interface RemoveAfter {
/**
diff --git a/java/com/google/gerrit/extensions/common/testing/RobotCommentInfoSubject.java b/java/com/google/gerrit/extensions/common/testing/RobotCommentInfoSubject.java
index 0698735..dd226ed 100644
--- a/java/com/google/gerrit/extensions/common/testing/RobotCommentInfoSubject.java
+++ b/java/com/google/gerrit/extensions/common/testing/RobotCommentInfoSubject.java
@@ -18,6 +18,7 @@
import static com.google.gerrit.truth.ListSubject.elements;
import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.gerrit.extensions.common.FixSuggestionInfo;
import com.google.gerrit.extensions.common.RobotCommentInfo;
@@ -53,6 +54,11 @@
.thatCustom(robotCommentInfo.fixSuggestions, FixSuggestionInfoSubject.fixSuggestions());
}
+ public StringSubject path() {
+ isNotNull();
+ return check("path").that(robotCommentInfo.path);
+ }
+
public FixSuggestionInfoSubject onlyFixSuggestion() {
return fixSuggestions().onlyElement();
}
diff --git a/java/com/google/gerrit/server/CommentsUtil.java b/java/com/google/gerrit/server/CommentsUtil.java
index e9ba72d..450cbe0 100644
--- a/java/com/google/gerrit/server/CommentsUtil.java
+++ b/java/com/google/gerrit/server/CommentsUtil.java
@@ -242,7 +242,9 @@
* @param changeMessages list of change messages
*/
public static void linkCommentsToChangeMessages(
- List<? extends CommentInfo> comments, List<ChangeMessage> changeMessages) {
+ List<? extends CommentInfo> comments,
+ List<ChangeMessage> changeMessages,
+ boolean skipAutoGeneratedMessages) {
ArrayList<ChangeMessage> sortedChangeMessages =
changeMessages.stream()
.sorted(comparing(ChangeMessage::getWrittenOn))
@@ -257,7 +259,7 @@
// message in timestamp
while (cmItr < sortedChangeMessages.size()) {
ChangeMessage cm = sortedChangeMessages.get(cmItr);
- if (isAfter(comment, cm) || skipChangeMessage(cm)) {
+ if (isAfter(comment, cm) || (skipAutoGeneratedMessages && isAutoGenerated(cm))) {
cmItr += 1;
} else {
break;
@@ -269,7 +271,7 @@
}
}
- private static boolean skipChangeMessage(ChangeMessage cm) {
+ private static boolean isAutoGenerated(ChangeMessage cm) {
return ChangeMessagesUtil.isAutogenerated(cm.getTag());
}
diff --git a/java/com/google/gerrit/server/account/StoredPreferences.java b/java/com/google/gerrit/server/account/StoredPreferences.java
index 1b3ff40..573c619 100644
--- a/java/com/google/gerrit/server/account/StoredPreferences.java
+++ b/java/com/google/gerrit/server/account/StoredPreferences.java
@@ -15,19 +15,13 @@
package com.google.gerrit.server.account;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.gerrit.server.config.ConfigUtil.loadSection;
-import static com.google.gerrit.server.config.ConfigUtil.skipField;
import static com.google.gerrit.server.config.ConfigUtil.storeSection;
-import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE;
import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
import static java.util.Objects.requireNonNull;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
@@ -36,13 +30,12 @@
import com.google.gerrit.extensions.client.MenuItem;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.PreferencesParserUtil;
import com.google.gerrit.server.config.VersionedDefaultPreferences;
import com.google.gerrit.server.git.UserConfigSections;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -76,8 +69,6 @@
* <p>The preferences are lazily parsed.
*/
public class StoredPreferences {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
public static final String PREFERENCES_CONFIG = "preferences.config";
private final Account.Id accountId;
@@ -141,7 +132,7 @@
UserConfigSections.GENERAL,
null,
mergedGeneralPreferencesInput,
- parseDefaultGeneralPreferences(defaultCfg, null));
+ PreferencesParserUtil.parseDefaultGeneralPreferences(defaultCfg, null));
setChangeTable(cfg, mergedGeneralPreferencesInput.changeTable);
setMy(cfg, mergedGeneralPreferencesInput.my);
@@ -158,7 +149,7 @@
UserConfigSections.DIFF,
null,
mergedDiffPreferencesInput,
- parseDefaultDiffPreferences(defaultCfg, null));
+ PreferencesParserUtil.parseDefaultDiffPreferences(defaultCfg, null));
// evict the cached diff preferences
this.diffPreferences = null;
@@ -173,7 +164,7 @@
UserConfigSections.EDIT,
null,
mergedEditPreferencesInput,
- parseDefaultEditPreferences(defaultCfg, null));
+ PreferencesParserUtil.parseDefaultEditPreferences(defaultCfg, null));
// evict the cached edit preferences
this.editPreferences = null;
@@ -189,7 +180,7 @@
private GeneralPreferencesInfo parseGeneralPreferences(@Nullable GeneralPreferencesInfo input) {
try {
- return parseGeneralPreferences(cfg, defaultCfg, input);
+ return PreferencesParserUtil.parseGeneralPreferences(cfg, defaultCfg, input);
} catch (ConfigInvalidException e) {
validationErrorSink.error(
new ValidationError(
@@ -203,7 +194,7 @@
private DiffPreferencesInfo parseDiffPreferences(@Nullable DiffPreferencesInfo input) {
try {
- return parseDiffPreferences(cfg, defaultCfg, input);
+ return PreferencesParserUtil.parseDiffPreferences(cfg, defaultCfg, input);
} catch (ConfigInvalidException e) {
validationErrorSink.error(
new ValidationError(
@@ -216,7 +207,7 @@
private EditPreferencesInfo parseEditPreferences(@Nullable EditPreferencesInfo input) {
try {
- return parseEditPreferences(cfg, defaultCfg, input);
+ return PreferencesParserUtil.parseEditPreferences(cfg, defaultCfg, input);
} catch (ConfigInvalidException e) {
validationErrorSink.error(
new ValidationError(
@@ -227,218 +218,6 @@
}
}
- /**
- * Returns a {@link GeneralPreferencesInfo} that is the result of parsing {@code defaultCfg} for
- * the server's default configs and {@code cfg} for the user's config. These configs are then
- * overlaid to inherit values (default -> user -> input (if provided).
- */
- public static GeneralPreferencesInfo parseGeneralPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable GeneralPreferencesInfo input)
- throws ConfigInvalidException {
- GeneralPreferencesInfo r =
- loadSection(
- cfg,
- UserConfigSections.GENERAL,
- null,
- new GeneralPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultGeneralPreferences(defaultCfg, input)
- : GeneralPreferencesInfo.defaults(),
- input);
- if (input != null) {
- r.changeTable = input.changeTable;
- r.my = input.my;
- } else {
- r.changeTable = parseChangeTableColumns(cfg, defaultCfg);
- r.my = parseMyMenus(cfg, defaultCfg);
- }
- return r;
- }
-
- /**
- * Returns a {@link DiffPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
- * server's default configs and {@code cfg} for the user's config. These configs are then overlaid
- * to inherit values (default -> user -> input (if provided).
- */
- public static DiffPreferencesInfo parseDiffPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable DiffPreferencesInfo input)
- throws ConfigInvalidException {
- return loadSection(
- cfg,
- UserConfigSections.DIFF,
- null,
- new DiffPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultDiffPreferences(defaultCfg, input)
- : DiffPreferencesInfo.defaults(),
- input);
- }
-
- /**
- * Returns a {@link EditPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
- * server's default configs and {@code cfg} for the user's config. These configs are then overlaid
- * to inherit values (default -> user -> input (if provided).
- */
- public static EditPreferencesInfo parseEditPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable EditPreferencesInfo input)
- throws ConfigInvalidException {
- return loadSection(
- cfg,
- UserConfigSections.EDIT,
- null,
- new EditPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultEditPreferences(defaultCfg, input)
- : EditPreferencesInfo.defaults(),
- input);
- }
-
- private static GeneralPreferencesInfo parseDefaultGeneralPreferences(
- Config defaultCfg, GeneralPreferencesInfo input) throws ConfigInvalidException {
- GeneralPreferencesInfo allUserPrefs = new GeneralPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.GENERAL,
- null,
- allUserPrefs,
- GeneralPreferencesInfo.defaults(),
- input);
- return updateGeneralPreferencesDefaults(allUserPrefs);
- }
-
- private static DiffPreferencesInfo parseDefaultDiffPreferences(
- Config defaultCfg, DiffPreferencesInfo input) throws ConfigInvalidException {
- DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.DIFF,
- null,
- allUserPrefs,
- DiffPreferencesInfo.defaults(),
- input);
- return updateDiffPreferencesDefaults(allUserPrefs);
- }
-
- private static EditPreferencesInfo parseDefaultEditPreferences(
- Config defaultCfg, EditPreferencesInfo input) throws ConfigInvalidException {
- EditPreferencesInfo allUserPrefs = new EditPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.EDIT,
- null,
- allUserPrefs,
- EditPreferencesInfo.defaults(),
- input);
- return updateEditPreferencesDefaults(allUserPrefs);
- }
-
- private static GeneralPreferencesInfo updateGeneralPreferencesDefaults(
- GeneralPreferencesInfo input) {
- GeneralPreferencesInfo result = GeneralPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default general preferences");
- return GeneralPreferencesInfo.defaults();
- }
- return result;
- }
-
- private static DiffPreferencesInfo updateDiffPreferencesDefaults(DiffPreferencesInfo input) {
- DiffPreferencesInfo result = DiffPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default diff preferences");
- return DiffPreferencesInfo.defaults();
- }
- return result;
- }
-
- private static EditPreferencesInfo updateEditPreferencesDefaults(EditPreferencesInfo input) {
- EditPreferencesInfo result = EditPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default edit preferences");
- return EditPreferencesInfo.defaults();
- }
- return result;
- }
-
- private static List<String> parseChangeTableColumns(Config cfg, @Nullable Config defaultCfg) {
- List<String> changeTable = changeTable(cfg);
- if (changeTable == null && defaultCfg != null) {
- changeTable = changeTable(defaultCfg);
- }
- return changeTable;
- }
-
- private static List<MenuItem> parseMyMenus(Config cfg, @Nullable Config defaultCfg) {
- List<MenuItem> my = my(cfg);
- if (my.isEmpty() && defaultCfg != null) {
- my = my(defaultCfg);
- }
- if (my.isEmpty()) {
- my.add(new MenuItem("Dashboard", "#/dashboard/self", null));
- my.add(new MenuItem("Draft Comments", "#/q/has:draft", null));
- my.add(new MenuItem("Edits", "#/q/has:edit", null));
- my.add(new MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
- my.add(new MenuItem("Starred Changes", "#/q/is:starred", null));
- my.add(new MenuItem("Groups", "#/settings/#Groups", null));
- }
- return my;
- }
-
- public static GeneralPreferencesInfo readDefaultGeneralPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseGeneralPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
-
- public static DiffPreferencesInfo readDefaultDiffPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseDiffPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
-
- public static EditPreferencesInfo readDefaultEditPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseEditPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
-
- static Config readDefaultConfig(AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
- defaultPrefs.load(allUsersName, allUsersRepo);
- return defaultPrefs.getConfig();
- }
-
public static GeneralPreferencesInfo updateDefaultGeneralPreferences(
MetaDataUpdate md, GeneralPreferencesInfo input) throws IOException, ConfigInvalidException {
VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
@@ -453,7 +232,7 @@
setChangeTable(defaultPrefs.getConfig(), input.changeTable);
defaultPrefs.commit(md);
- return parseGeneralPreferences(defaultPrefs.getConfig(), null, null);
+ return PreferencesParserUtil.parseGeneralPreferences(defaultPrefs.getConfig(), null, null);
}
public static DiffPreferencesInfo updateDefaultDiffPreferences(
@@ -468,7 +247,7 @@
DiffPreferencesInfo.defaults());
defaultPrefs.commit(md);
- return parseDiffPreferences(defaultPrefs.getConfig(), null, null);
+ return PreferencesParserUtil.parseDiffPreferences(defaultPrefs.getConfig(), null, null);
}
public static EditPreferencesInfo updateDefaultEditPreferences(
@@ -483,11 +262,24 @@
EditPreferencesInfo.defaults());
defaultPrefs.commit(md);
- return parseEditPreferences(defaultPrefs.getConfig(), null, null);
+ return PreferencesParserUtil.parseEditPreferences(defaultPrefs.getConfig(), null, null);
}
- private static List<String> changeTable(Config cfg) {
- return Lists.newArrayList(cfg.getStringList(CHANGE_TABLE, null, CHANGE_TABLE_COLUMN));
+ public static void validateMy(List<MenuItem> my) throws BadRequestException {
+ if (my == null) {
+ return;
+ }
+ for (MenuItem item : my) {
+ checkRequiredMenuItemField(item.name, "name");
+ checkRequiredMenuItemField(item.url, "URL");
+ }
+ }
+
+ static Config readDefaultConfig(AllUsersName allUsersName, Repository allUsersRepo)
+ throws IOException, ConfigInvalidException {
+ VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
+ defaultPrefs.load(allUsersName, allUsersRepo);
+ return defaultPrefs.getConfig();
}
private static void setChangeTable(Config cfg, List<String> changeTable) {
@@ -497,21 +289,6 @@
}
}
- private static List<MenuItem> my(Config cfg) {
- List<MenuItem> my = new ArrayList<>();
- for (String subsection : cfg.getSubsections(UserConfigSections.MY)) {
- String url = my(cfg, subsection, KEY_URL, "#/");
- String target = my(cfg, subsection, KEY_TARGET, url.startsWith("#") ? null : "_blank");
- my.add(new MenuItem(subsection, url, target, my(cfg, subsection, KEY_ID, null)));
- }
- return my;
- }
-
- private static String my(Config cfg, String subsection, String key, String defaultValue) {
- String val = cfg.getString(UserConfigSections.MY, subsection, key);
- return !Strings.isNullOrEmpty(val) ? val : defaultValue;
- }
-
private static void setMy(Config cfg, List<MenuItem> my) {
if (my != null) {
unsetSection(cfg, UserConfigSections.MY);
@@ -526,16 +303,6 @@
}
}
- public static void validateMy(List<MenuItem> my) throws BadRequestException {
- if (my == null) {
- return;
- }
- for (MenuItem item : my) {
- checkRequiredMenuItemField(item.name, "name");
- checkRequiredMenuItemField(item.url, "URL");
- }
- }
-
private static void checkRequiredMenuItemField(String value, String name)
throws BadRequestException {
if (isNullOrEmpty(value)) {
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 8c4f275..8f97b68 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -140,7 +140,6 @@
COMMIT_FOOTERS,
CURRENT_ACTIONS,
CURRENT_COMMIT,
- DETAILED_LABELS, // may need to load ChangeNotes to check remove reviewer permissions
MESSAGES);
@Singleton
@@ -722,7 +721,10 @@
// testRemoveReviewer check for a specific reviewer in the loop saving potentially many
// permission checks.
boolean canRemoveAnyReviewer =
- permissionBackendForChange(userProvider.get(), cd).test(ChangePermission.REMOVE_REVIEWER);
+ permissionBackend
+ .user(userProvider.get())
+ .change(cd)
+ .test(ChangePermission.REMOVE_REVIEWER);
for (LabelInfo label : labels) {
if (label.all == null) {
continue;
@@ -817,16 +819,4 @@
}
return map;
}
-
- /**
- * @return {@link com.google.gerrit.server.permissions.PermissionBackend.ForChange} constructed
- * from either an index-backed or a database-backed {@link ChangeData} depending on {@code
- * lazyload}.
- */
- private PermissionBackend.ForChange permissionBackendForChange(CurrentUser user, ChangeData cd) {
- PermissionBackend.WithUser withUser = permissionBackend.user(user);
- return lazyLoad
- ? withUser.change(cd)
- : withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
- }
}
diff --git a/java/com/google/gerrit/server/change/DeleteReviewerOp.java b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
index b70b059..099334d 100644
--- a/java/com/google/gerrit/server/change/DeleteReviewerOp.java
+++ b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
@@ -49,10 +49,8 @@
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
public class DeleteReviewerOp implements BatchUpdateOp {
@@ -134,12 +132,10 @@
msg.append("Removed reviewer " + reviewer.account().fullName());
StringBuilder removedVotesMsg = new StringBuilder();
removedVotesMsg.append(" with the following votes:\n\n");
- List<PatchSetApproval> del = new ArrayList<>();
boolean votesRemoved = false;
for (PatchSetApproval a : approvals(ctx, reviewerId)) {
// Check if removing this vote is OK
removeReviewerControl.checkRemoveReviewer(ctx.getNotes(), ctx.getUser(), a);
- del.add(a);
if (a.patchSetId().equals(currPs.id()) && a.value() != 0) {
oldApprovals.put(a.label(), a.value());
removedVotesMsg
diff --git a/java/com/google/gerrit/server/change/LabelsJson.java b/java/com/google/gerrit/server/change/LabelsJson.java
index c6f4969..2db17d6 100644
--- a/java/com/google/gerrit/server/change/LabelsJson.java
+++ b/java/com/google/gerrit/server/change/LabelsJson.java
@@ -131,7 +131,7 @@
Map<String, Short> labels = null;
Set<LabelPermission.WithValue> can =
- permissionBackendForChange(filterApprovalsBy, cd).testLabels(toCheck.values());
+ permissionBackend.absentUser(filterApprovalsBy).change(cd).testLabels(toCheck.values());
SetMultimap<String, String> permitted = LinkedHashMultimap.create();
for (SubmitRecord rec : submitRecords(cd)) {
if (rec.labels == null) {
@@ -452,7 +452,7 @@
LabelTypes labelTypes = cd.getLabelTypes();
for (Account.Id accountId : allUsers) {
- PermissionBackend.ForChange perm = permissionBackendForChange(accountId, cd);
+ PermissionBackend.ForChange perm = permissionBackend.absentUser(accountId).change(cd);
Map<String, VotingRangeInfo> pvr = getPermittedVotingRanges(permittedLabels(accountId, cd));
for (Map.Entry<String, LabelWithStatus> e : labels.entrySet()) {
LabelType lt = labelTypes.byLabel(e.getKey());
@@ -492,18 +492,6 @@
}
}
- /**
- * @return {@link com.google.gerrit.server.permissions.PermissionBackend.ForChange} constructed
- * from either an index-backed or a database-backed {@link ChangeData} depending on {@code
- * lazyload}.
- */
- private PermissionBackend.ForChange permissionBackendForChange(Account.Id user, ChangeData cd) {
- PermissionBackend.WithUser withUser = permissionBackend.absentUser(user);
- return lazyLoad
- ? withUser.change(cd)
- : withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
- }
-
private List<SubmitRecord> submitRecords(ChangeData cd) {
return cd.submitRecords(ChangeJson.SUBMIT_RULE_OPTIONS_LENIENT);
}
diff --git a/java/com/google/gerrit/server/change/RevisionJson.java b/java/com/google/gerrit/server/change/RevisionJson.java
index 001a532..414107f 100644
--- a/java/com/google/gerrit/server/change/RevisionJson.java
+++ b/java/com/google/gerrit/server/change/RevisionJson.java
@@ -31,7 +31,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Change;
@@ -60,7 +59,6 @@
import com.google.gerrit.server.account.GpgApiAdapter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -107,8 +105,6 @@
private final AnonymousUser anonymous;
private final GitRepositoryManager repoManager;
private final PermissionBackend permissionBackend;
- private final ChangeNotes.Factory notesFactory;
- private final boolean lazyLoad;
@Inject
RevisionJson(
@@ -128,7 +124,6 @@
ChangeKindCache changeKindCache,
GitRepositoryManager repoManager,
PermissionBackend permissionBackend,
- ChangeNotes.Factory notesFactory,
@Assisted Iterable<ListChangesOption> options) {
this.userProvider = userProvider;
this.anonymous = anonymous;
@@ -145,10 +140,8 @@
this.changeResourceFactory = changeResourceFactory;
this.changeKindCache = changeKindCache;
this.permissionBackend = permissionBackend;
- this.notesFactory = notesFactory;
this.repoManager = repoManager;
this.options = ImmutableSet.copyOf(options);
- this.lazyLoad = containsAnyOf(this.options, ChangeJson.REQUIRE_LAZY_LOAD);
}
/**
@@ -346,22 +339,9 @@
return options.contains(option);
}
- /**
- * @return {@link com.google.gerrit.server.permissions.PermissionBackend.ForChange} constructed
- * from either an index-backed or a database-backed {@link ChangeData} depending on {@code
- * lazyload}.
- */
- private PermissionBackend.ForChange permissionBackendForChange(
- PermissionBackend.WithUser withUser, ChangeData cd) {
- return lazyLoad
- ? withUser.change(cd)
- : withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
- }
-
private boolean isWorldReadable(ChangeData cd) throws PermissionBackendException {
try {
- permissionBackendForChange(permissionBackend.user(anonymous), cd)
- .check(ChangePermission.READ);
+ permissionBackend.user(anonymous).change(cd).check(ChangePermission.READ);
} catch (AuthException ae) {
return false;
}
@@ -382,9 +362,4 @@
private RevWalk newRevWalk(@Nullable Repository repo) {
return repo != null ? new RevWalk(repo) : null;
}
-
- private static boolean containsAnyOf(
- ImmutableSet<ListChangesOption> set, ImmutableSet<ListChangesOption> toFind) {
- return !Sets.intersection(toFind, set).isEmpty();
- }
}
diff --git a/java/com/google/gerrit/server/config/CachedPreferences.java b/java/com/google/gerrit/server/config/CachedPreferences.java
index f4dcd10..388f58a 100644
--- a/java/com/google/gerrit/server/config/CachedPreferences.java
+++ b/java/com/google/gerrit/server/config/CachedPreferences.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
-import com.google.gerrit.server.account.StoredPreferences;
import java.util.Optional;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
@@ -52,7 +51,7 @@
public static GeneralPreferencesInfo general(
Optional<CachedPreferences> defaultPreferences, CachedPreferences userPreferences) {
try {
- return StoredPreferences.parseGeneralPreferences(
+ return PreferencesParserUtil.parseGeneralPreferences(
userPreferences.asConfig(), configOrNull(defaultPreferences), null);
} catch (ConfigInvalidException e) {
return GeneralPreferencesInfo.defaults();
@@ -62,7 +61,7 @@
public static EditPreferencesInfo edit(
Optional<CachedPreferences> defaultPreferences, CachedPreferences userPreferences) {
try {
- return StoredPreferences.parseEditPreferences(
+ return PreferencesParserUtil.parseEditPreferences(
userPreferences.asConfig(), configOrNull(defaultPreferences), null);
} catch (ConfigInvalidException e) {
return EditPreferencesInfo.defaults();
@@ -72,7 +71,7 @@
public static DiffPreferencesInfo diff(
Optional<CachedPreferences> defaultPreferences, CachedPreferences userPreferences) {
try {
- return StoredPreferences.parseDiffPreferences(
+ return PreferencesParserUtil.parseDiffPreferences(
userPreferences.asConfig(), configOrNull(defaultPreferences), null);
} catch (ConfigInvalidException e) {
return DiffPreferencesInfo.defaults();
diff --git a/java/com/google/gerrit/server/config/PreferencesParserUtil.java b/java/com/google/gerrit/server/config/PreferencesParserUtil.java
new file mode 100644
index 0000000..69d75be
--- /dev/null
+++ b/java/com/google/gerrit/server/config/PreferencesParserUtil.java
@@ -0,0 +1,266 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.config;
+
+import static com.google.gerrit.server.config.ConfigUtil.loadSection;
+import static com.google.gerrit.server.config.ConfigUtil.skipField;
+import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE;
+import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.EditPreferencesInfo;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.extensions.client.MenuItem;
+import com.google.gerrit.server.git.UserConfigSections;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+
+/** Helper to read default or user preferences from Git-style config files. */
+public class PreferencesParserUtil {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private PreferencesParserUtil() {}
+
+ /**
+ * Returns a {@link GeneralPreferencesInfo} that is the result of parsing {@code defaultCfg} for
+ * the server's default configs and {@code cfg} for the user's config. These configs are then
+ * overlaid to inherit values (default -> user -> input (if provided).
+ */
+ public static GeneralPreferencesInfo parseGeneralPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable GeneralPreferencesInfo input)
+ throws ConfigInvalidException {
+ GeneralPreferencesInfo r =
+ loadSection(
+ cfg,
+ UserConfigSections.GENERAL,
+ null,
+ new GeneralPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultGeneralPreferences(defaultCfg, input)
+ : GeneralPreferencesInfo.defaults(),
+ input);
+ if (input != null) {
+ r.changeTable = input.changeTable;
+ r.my = input.my;
+ } else {
+ r.changeTable = parseChangeTableColumns(cfg, defaultCfg);
+ r.my = parseMyMenus(cfg, defaultCfg);
+ }
+ return r;
+ }
+
+ /**
+ * Returns a {@link GeneralPreferencesInfo} that is the result of parsing {@code defaultCfg} for
+ * the server's default configs. These configs are then overlaid to inherit values (default ->
+ * input (if provided).
+ */
+ public static GeneralPreferencesInfo parseDefaultGeneralPreferences(
+ Config defaultCfg, GeneralPreferencesInfo input) throws ConfigInvalidException {
+ GeneralPreferencesInfo allUserPrefs = new GeneralPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.GENERAL,
+ null,
+ allUserPrefs,
+ GeneralPreferencesInfo.defaults(),
+ input);
+ return updateGeneralPreferencesDefaults(allUserPrefs);
+ }
+
+ /**
+ * Returns a {@link DiffPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
+ * server's default configs and {@code cfg} for the user's config. These configs are then overlaid
+ * to inherit values (default -> user -> input (if provided).
+ */
+ public static DiffPreferencesInfo parseDiffPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable DiffPreferencesInfo input)
+ throws ConfigInvalidException {
+ return loadSection(
+ cfg,
+ UserConfigSections.DIFF,
+ null,
+ new DiffPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultDiffPreferences(defaultCfg, input)
+ : DiffPreferencesInfo.defaults(),
+ input);
+ }
+
+ /**
+ * Returns a {@link DiffPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
+ * server's default configs. These configs are then overlaid to inherit values (default -> input
+ * (if provided).
+ */
+ public static DiffPreferencesInfo parseDefaultDiffPreferences(
+ Config defaultCfg, DiffPreferencesInfo input) throws ConfigInvalidException {
+ DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.DIFF,
+ null,
+ allUserPrefs,
+ DiffPreferencesInfo.defaults(),
+ input);
+ return updateDiffPreferencesDefaults(allUserPrefs);
+ }
+
+ /**
+ * Returns a {@link EditPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
+ * server's default configs and {@code cfg} for the user's config. These configs are then overlaid
+ * to inherit values (default -> user -> input (if provided).
+ */
+ public static EditPreferencesInfo parseEditPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable EditPreferencesInfo input)
+ throws ConfigInvalidException {
+ return loadSection(
+ cfg,
+ UserConfigSections.EDIT,
+ null,
+ new EditPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultEditPreferences(defaultCfg, input)
+ : EditPreferencesInfo.defaults(),
+ input);
+ }
+
+ /**
+ * Returns a {@link EditPreferencesInfo} that is the result of parsing {@code defaultCfg} for the
+ * server's default configs. These configs are then overlaid to inherit values (default -> input
+ * (if provided).
+ */
+ public static EditPreferencesInfo parseDefaultEditPreferences(
+ Config defaultCfg, EditPreferencesInfo input) throws ConfigInvalidException {
+ EditPreferencesInfo allUserPrefs = new EditPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.EDIT,
+ null,
+ allUserPrefs,
+ EditPreferencesInfo.defaults(),
+ input);
+ return updateEditPreferencesDefaults(allUserPrefs);
+ }
+
+ private static List<String> parseChangeTableColumns(Config cfg, @Nullable Config defaultCfg) {
+ List<String> changeTable = changeTable(cfg);
+ if (changeTable == null && defaultCfg != null) {
+ changeTable = changeTable(defaultCfg);
+ }
+ return changeTable;
+ }
+
+ private static List<MenuItem> parseMyMenus(Config cfg, @Nullable Config defaultCfg) {
+ List<MenuItem> my = my(cfg);
+ if (my.isEmpty() && defaultCfg != null) {
+ my = my(defaultCfg);
+ }
+ if (my.isEmpty()) {
+ my.add(new MenuItem("Dashboard", "#/dashboard/self", null));
+ my.add(new MenuItem("Draft Comments", "#/q/has:draft", null));
+ my.add(new MenuItem("Edits", "#/q/has:edit", null));
+ my.add(new MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
+ my.add(new MenuItem("Starred Changes", "#/q/is:starred", null));
+ my.add(new MenuItem("Groups", "#/settings/#Groups", null));
+ }
+ return my;
+ }
+
+ private static GeneralPreferencesInfo updateGeneralPreferencesDefaults(
+ GeneralPreferencesInfo input) {
+ GeneralPreferencesInfo result = GeneralPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default general preferences");
+ return GeneralPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static DiffPreferencesInfo updateDiffPreferencesDefaults(DiffPreferencesInfo input) {
+ DiffPreferencesInfo result = DiffPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default diff preferences");
+ return DiffPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static EditPreferencesInfo updateEditPreferencesDefaults(EditPreferencesInfo input) {
+ EditPreferencesInfo result = EditPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default edit preferences");
+ return EditPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static List<String> changeTable(Config cfg) {
+ return Lists.newArrayList(cfg.getStringList(CHANGE_TABLE, null, CHANGE_TABLE_COLUMN));
+ }
+
+ private static List<MenuItem> my(Config cfg) {
+ List<MenuItem> my = new ArrayList<>();
+ for (String subsection : cfg.getSubsections(UserConfigSections.MY)) {
+ String url = my(cfg, subsection, KEY_URL, "#/");
+ String target = my(cfg, subsection, KEY_TARGET, url.startsWith("#") ? null : "_blank");
+ my.add(new MenuItem(subsection, url, target, my(cfg, subsection, KEY_ID, null)));
+ }
+ return my;
+ }
+
+ private static String my(Config cfg, String subsection, String key, String defaultValue) {
+ String val = cfg.getString(UserConfigSections.MY, subsection, key);
+ return !Strings.isNullOrEmpty(val) ? val : defaultValue;
+ }
+}
diff --git a/java/com/google/gerrit/server/documentation/MarkdownFormatter.java b/java/com/google/gerrit/server/documentation/MarkdownFormatter.java
index 2eb46f1..2d5e708 100644
--- a/java/com/google/gerrit/server/documentation/MarkdownFormatter.java
+++ b/java/com/google/gerrit/server/documentation/MarkdownFormatter.java
@@ -21,7 +21,6 @@
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
-import com.vladsch.flexmark.Extension;
import com.vladsch.flexmark.ast.Block;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.ast.Node;
@@ -36,7 +35,6 @@
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang.StringEscapeUtils;
import org.eclipse.jgit.util.RawParseUtils;
@@ -95,11 +93,6 @@
options, MarkdownFormatterHeader.HeadingExtension.create())
.toMutable();
- ArrayList<Extension> extensions = new ArrayList<>();
- for (Extension extension : optionsExt.get(com.vladsch.flexmark.parser.Parser.EXTENSIONS)) {
- extensions.add(extension);
- }
-
return optionsExt;
}
diff --git a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
index 196fc61..fed6541 100644
--- a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
+++ b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
@@ -165,7 +165,7 @@
List<CachedChange> result = new ArrayList<>(cds.size());
for (ChangeData cd : cds) {
result.add(
- new AutoValue_SearchingChangeCacheImpl_CachedChange(cd.change(), cd.getReviewers()));
+ new AutoValue_SearchingChangeCacheImpl_CachedChange(cd.change(), cd.reviewers()));
}
return Collections.unmodifiableList(result);
}
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index 0d762c7..2177485 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -417,6 +417,16 @@
metrics.latencyPerPush.record(pushType, deltaNanos, NANOSECONDS);
}
+ /**
+ * Sends all messages which have been collected while processing the push to the client.
+ *
+ * @see ReceiveCommits#sendMessages()
+ */
+ @UsedAt(UsedAt.Project.GOOGLE)
+ public void sendMessages() {
+ receiveCommits.sendMessages();
+ }
+
public ReceivePack getReceivePack() {
return receivePack;
}
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index a845e53..404fa3c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -737,7 +737,7 @@
Set<BranchNameKey> branches = new HashSet<>();
for (ReceiveCommand c : cmds) {
// Most post-update steps should happen in UpdateOneRefOp#postUpdate. The only steps that
- // should happen in this loop are things that can't happen within one BatchUpdate because
+ // should happen in this loops are things that can't happen within one BatchUpdate because
// they involve kicking off an additional BatchUpdate.
if (c.getResult() != OK) {
continue;
@@ -3238,6 +3238,13 @@
ObjectInserter ins = repo.newObjectInserter();
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
+ if (ObjectId.zeroId().equals(cmd.getOldId())) {
+ // The user is creating a new branch. The branch can't contain any changes, so
+ // auto-closing doesn't apply. Exiting here early to spare any further,
+ // potentially expensive computation that loop over all commits.
+ return null;
+ }
+
bu.setRepository(repo, rw, ins);
// TODO(dborowitz): Teach BatchUpdate to ignore missing changes.
@@ -3247,9 +3254,7 @@
rw.reset();
rw.sort(RevSort.REVERSE);
rw.markStart(newTip);
- if (!ObjectId.zeroId().equals(cmd.getOldId())) {
- rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
- }
+ rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
Map<Change.Key, ChangeNotes> byKey = null;
List<ReplaceRequest> replaceAndClose = new ArrayList<>();
@@ -3261,6 +3266,8 @@
for (RevCommit c; (c = rw.next()) != null; ) {
rw.parseBody(c);
+ // Check if change refs point to this commit. Usually there are 0-1 change
+ // refs pointing to this commit.
for (Ref ref :
receivePackRefCache.tipsFromObjectId(c.copy(), RefNames.REFS_CHANGES)) {
PatchSet.Id psId = PatchSet.Id.fromRef(ref.getName());
@@ -3360,6 +3367,8 @@
logger.atSevere().withCause(e).log("Can't insert patchset");
} catch (UpdateException e) {
logger.atSevere().withCause(e).log("Failed to auto-close changes");
+ } finally {
+ logger.atFine().log("Done auto-closing changes");
}
}
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java b/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
index 4b538f3..07b58f2 100644
--- a/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
+++ b/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
@@ -19,7 +19,6 @@
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.Sets;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Comment;
@@ -37,7 +36,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.ObjectId;
@@ -191,7 +189,6 @@
RevWalk rw, ObjectInserter ins, ObjectId curr, CommitBuilder cb)
throws ConfigInvalidException, IOException {
RevisionNoteMap<ChangeRevisionNote> rnm = getRevisionNoteMap(rw, curr);
- Set<ObjectId> updatedCommits = Sets.newHashSetWithExpectedSize(rnm.revisionNotes.size());
RevisionNoteBuilder.Cache cache = new RevisionNoteBuilder.Cache(rnm);
for (Comment c : put) {
@@ -207,7 +204,6 @@
Map<ObjectId, RevisionNoteBuilder> builders = cache.getBuilders();
boolean touchedAnyRevs = false;
for (Map.Entry<ObjectId, RevisionNoteBuilder> e : builders.entrySet()) {
- updatedCommits.add(e.getKey());
ObjectId id = e.getKey();
byte[] data = e.getValue().build(noteUtil.getChangeNoteJson());
if (!Arrays.equals(data, e.getValue().baseRaw)) {
diff --git a/java/com/google/gerrit/server/patch/PatchList.java b/java/com/google/gerrit/server/patch/PatchList.java
index c9e45ba..28f61d3 100644
--- a/java/com/google/gerrit/server/patch/PatchList.java
+++ b/java/com/google/gerrit/server/patch/PatchList.java
@@ -45,23 +45,12 @@
public class PatchList implements Serializable {
private static final long serialVersionUID = PatchListKey.serialVersionUID;
- private static final Comparator<PatchListEntry> PATCH_CMP =
- Comparator.comparing(PatchListEntry::getNewName, PatchList::comparePaths);
-
@VisibleForTesting
- static int comparePaths(String a, String b) {
- int m1 = Patch.isMagic(a) ? (a.equals(Patch.MERGE_LIST) ? 2 : 1) : 3;
- int m2 = Patch.isMagic(b) ? (b.equals(Patch.MERGE_LIST) ? 2 : 1) : 3;
+ static final Comparator<String> FILE_PATH_CMP =
+ Comparator.comparing(Patch::isMagic).reversed().thenComparing(Comparator.naturalOrder());
- if (m1 != m2) {
- return m1 - m2;
- } else if (m1 < 3) {
- return 0;
- }
-
- // m1 == m2 == 3: normal names.
- return a.compareTo(b);
- }
+ private static final Comparator<PatchListEntry> PATCH_CMP =
+ Comparator.comparing(PatchListEntry::getNewName, FILE_PATH_CMP);
@Nullable private transient ObjectId oldId;
private transient ObjectId newId;
diff --git a/java/com/google/gerrit/server/permissions/ChangeControl.java b/java/com/google/gerrit/server/permissions/ChangeControl.java
index 143547b..9f216c0 100644
--- a/java/com/google/gerrit/server/permissions/ChangeControl.java
+++ b/java/com/google/gerrit/server/permissions/ChangeControl.java
@@ -19,21 +19,16 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.conditions.BooleanCondition;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.PermissionBackend.ForChange;
import com.google.gerrit.server.query.change.ChangeData;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;
@@ -41,39 +36,16 @@
/** Access control management for a user accessing a single change. */
class ChangeControl {
- @Singleton
- static class Factory {
- private final ChangeData.Factory changeDataFactory;
- private final ChangeNotes.Factory notesFactory;
-
- @Inject
- Factory(ChangeData.Factory changeDataFactory, ChangeNotes.Factory notesFactory) {
- this.changeDataFactory = changeDataFactory;
- this.notesFactory = notesFactory;
- }
-
- ChangeControl create(RefControl refControl, Project.NameKey project, Change.Id changeId) {
- return create(refControl, notesFactory.create(project, changeId));
- }
-
- ChangeControl create(RefControl refControl, ChangeNotes notes) {
- return new ChangeControl(changeDataFactory, refControl, notes);
- }
- }
-
- private final ChangeData.Factory changeDataFactory;
private final RefControl refControl;
- private final ChangeNotes notes;
+ private final ChangeData changeData;
- private ChangeControl(
- ChangeData.Factory changeDataFactory, RefControl refControl, ChangeNotes notes) {
- this.changeDataFactory = changeDataFactory;
+ ChangeControl(RefControl refControl, ChangeData changeData) {
this.refControl = refControl;
- this.notes = notes;
+ this.changeData = changeData;
}
- ForChange asForChange(@Nullable ChangeData cd) {
- return new ForChangeImpl(cd);
+ ForChange asForChange() {
+ return new ForChangeImpl();
}
private CurrentUser getUser() {
@@ -85,7 +57,7 @@
}
private Change getChange() {
- return notes.getChange();
+ return changeData.change();
}
/** Can this user see this change? */
@@ -224,19 +196,13 @@
}
private class ForChangeImpl extends ForChange {
- private ChangeData cd;
private Map<String, PermissionRange> labels;
private String resourcePath;
- ForChangeImpl(@Nullable ChangeData cd) {
- this.cd = cd;
- }
+ private ForChangeImpl() {}
private ChangeData changeData() {
- if (cd == null) {
- cd = changeDataFactory.create(notes);
- }
- return cd;
+ return changeData;
}
@Override
diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionBackendModule.java b/java/com/google/gerrit/server/permissions/DefaultPermissionBackendModule.java
index f3a3c78..3f84dff 100644
--- a/java/com/google/gerrit/server/permissions/DefaultPermissionBackendModule.java
+++ b/java/com/google/gerrit/server/permissions/DefaultPermissionBackendModule.java
@@ -31,7 +31,6 @@
// TODO(hiesel) Hide ProjectControl, RefControl, ChangeControl related bindings.
factory(ProjectControl.Factory.class);
factory(DefaultRefFilter.Factory.class);
- bind(ChangeControl.Factory.class);
}
}
}
diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
index 90d9d88..4e1a30c 100644
--- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
+++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
@@ -448,12 +448,11 @@
try {
Map<Change.Id, BranchNameKey> visibleChanges = new HashMap<>();
for (ChangeData cd : changeCache.getChangeData(project)) {
- ChangeNotes notes = changeNotesFactory.createFromIndexedChange(cd.change());
if (!projectState.statePermitsRead()) {
continue;
}
try {
- permissionBackendForProject.indexedChange(cd, notes).check(ChangePermission.READ);
+ permissionBackendForProject.change(cd).check(ChangePermission.READ);
visibleChanges.put(cd.getId(), cd.change().getDest());
} catch (AuthException e) {
// Do nothing.
diff --git a/java/com/google/gerrit/server/permissions/FailedPermissionBackend.java b/java/com/google/gerrit/server/permissions/FailedPermissionBackend.java
index 2344781..749ca6b 100644
--- a/java/com/google/gerrit/server/permissions/FailedPermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/FailedPermissionBackend.java
@@ -173,11 +173,6 @@
}
@Override
- public ForChange indexedChange(ChangeData cd, ChangeNotes notes) {
- return new FailedChange(message, cause);
- }
-
- @Override
public void check(RefPermission perm) throws PermissionBackendException {
throw new PermissionBackendException(message, cause);
}
diff --git a/java/com/google/gerrit/server/permissions/PermissionBackend.java b/java/com/google/gerrit/server/permissions/PermissionBackend.java
index 653c3b5f..23145ba 100644
--- a/java/com/google/gerrit/server/permissions/PermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/PermissionBackend.java
@@ -173,15 +173,6 @@
return ref(notes.getChange().getDest()).change(notes);
}
- /**
- * Returns an instance scoped for the change loaded from index, and its destination ref and
- * project. This method should only be used when database access is harmful and potentially
- * stale data from the index is acceptable.
- */
- public ForChange indexedChange(ChangeData cd, ChangeNotes notes) {
- return ref(notes.getChange().getDest()).indexedChange(cd, notes);
- }
-
/** Verify scoped user can {@code perm}, throwing if denied. */
public abstract void check(GlobalOrPluginPermission perm)
throws AuthException, PermissionBackendException;
@@ -289,15 +280,6 @@
return ref(notes.getChange().getDest().branch()).change(notes);
}
- /**
- * Returns an instance scoped for the change loaded from index, and its destination ref and
- * project. This method should only be used when database access is harmful and potentially
- * stale data from the index is acceptable.
- */
- public ForChange indexedChange(ChangeData cd, ChangeNotes notes) {
- return ref(notes.getChange().getDest().branch()).indexedChange(cd, notes);
- }
-
/** Verify scoped user can {@code perm}, throwing if denied. */
public abstract void check(CoreOrPluginProjectPermission perm)
throws AuthException, PermissionBackendException;
@@ -386,12 +368,6 @@
/** Returns an instance scoped to change. */
public abstract ForChange change(ChangeNotes notes);
- /**
- * @return instance scoped to change loaded from index. This method should only be used when
- * database access is harmful and potentially stale data from the index is acceptable.
- */
- public abstract ForChange indexedChange(ChangeData cd, ChangeNotes notes);
-
/** Verify scoped user can {@code perm}, throwing if denied. */
public abstract void check(RefPermission perm) throws AuthException, PermissionBackendException;
diff --git a/java/com/google/gerrit/server/permissions/ProjectControl.java b/java/com/google/gerrit/server/permissions/ProjectControl.java
index 145e0b6..e6d66ee 100644
--- a/java/com/google/gerrit/server/permissions/ProjectControl.java
+++ b/java/com/google/gerrit/server/permissions/ProjectControl.java
@@ -70,9 +70,9 @@
private final PermissionBackend permissionBackend;
private final CurrentUser user;
private final ProjectState state;
- private final ChangeControl.Factory changeControlFactory;
private final PermissionCollection.Factory permissionFilter;
private final DefaultRefFilter.Factory refFilterFactory;
+ private final ChangeData.Factory changeDataFactory;
private List<SectionMatcher> allSections;
private Map<String, RefControl> refControls;
@@ -83,17 +83,17 @@
@GitUploadPackGroups Set<AccountGroup.UUID> uploadGroups,
@GitReceivePackGroups Set<AccountGroup.UUID> receiveGroups,
PermissionCollection.Factory permissionFilter,
- ChangeControl.Factory changeControlFactory,
PermissionBackend permissionBackend,
DefaultRefFilter.Factory refFilterFactory,
+ ChangeData.Factory changeDataFactory,
@Assisted CurrentUser who,
@Assisted ProjectState ps) {
- this.changeControlFactory = changeControlFactory;
this.uploadGroups = uploadGroups;
this.receiveGroups = receiveGroups;
this.permissionFilter = permissionFilter;
this.permissionBackend = permissionBackend;
this.refFilterFactory = refFilterFactory;
+ this.changeDataFactory = changeDataFactory;
user = who;
state = ps;
}
@@ -102,13 +102,8 @@
return new ForProjectImpl();
}
- ChangeControl controlFor(Change change) {
- return changeControlFactory.create(
- controlForRef(change.getDest()), change.getProject(), change.getId());
- }
-
- ChangeControl controlFor(ChangeNotes notes) {
- return changeControlFactory.create(controlForRef(notes.getChange().getDest()), notes);
+ ChangeControl controlFor(ChangeData cd) {
+ return new ChangeControl(controlForRef(cd.change().getDest()), cd);
}
RefControl controlForRef(BranchNameKey ref) {
@@ -122,7 +117,7 @@
RefControl ctl = refControls.get(refName);
if (ctl == null) {
PermissionCollection relevant = permissionFilter.filter(access(), refName, user);
- ctl = new RefControl(this, refName, relevant);
+ ctl = new RefControl(changeDataFactory, this, refName, relevant);
refControls.put(refName, ctl);
}
return ctl;
diff --git a/java/com/google/gerrit/server/permissions/RefControl.java b/java/com/google/gerrit/server/permissions/RefControl.java
index 7c5d6bd..5081116 100644
--- a/java/com/google/gerrit/server/permissions/RefControl.java
+++ b/java/com/google/gerrit/server/permissions/RefControl.java
@@ -43,6 +43,7 @@
class RefControl {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ChangeData.Factory changeDataFactory;
private final ProjectControl projectControl;
private final String refName;
@@ -58,7 +59,12 @@
private Boolean canForgeCommitter;
private Boolean isVisible;
- RefControl(ProjectControl projectControl, String ref, PermissionCollection relevant) {
+ RefControl(
+ ChangeData.Factory changeDataFactory,
+ ProjectControl projectControl,
+ String ref,
+ PermissionCollection relevant) {
+ this.changeDataFactory = changeDataFactory;
this.projectControl = projectControl;
this.refName = ref;
this.relevant = relevant;
@@ -444,7 +450,7 @@
@Override
public ForChange change(ChangeData cd) {
try {
- return getProjectControl().controlFor(cd.notes()).asForChange(cd);
+ return getProjectControl().controlFor(cd).asForChange();
} catch (StorageException e) {
return FailedPermissionBackend.change("unavailable", e);
}
@@ -459,12 +465,9 @@
"expected change in project %s, not %s",
project,
change.getProject());
- return getProjectControl().controlFor(notes).asForChange(null);
- }
-
- @Override
- public ForChange indexedChange(ChangeData cd, ChangeNotes notes) {
- return getProjectControl().controlFor(notes).asForChange(cd);
+ // Having ChangeNotes means it's OK to load values from NoteDb if needed.
+ // ChangeData.Factory will allow lazyLoading
+ return getProjectControl().controlFor(changeDataFactory.create(notes)).asForChange();
}
@Override
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index 69f1a4e..01d2c31 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -675,7 +675,9 @@
public ReviewerSet reviewers() {
if (reviewers == null) {
if (!lazyLoad) {
- return ReviewerSet.empty();
+ // We are not allowed to load values from NoteDb. Reviewers were not populated with values
+ // from the index. However, we need these values for permission checks.
+ throw new IllegalStateException("reviewers not populated");
}
reviewers = approvalsUtil.getReviewers(notes(), approvals().values());
}
@@ -686,10 +688,6 @@
this.reviewers = reviewers;
}
- public ReviewerSet getReviewers() {
- return reviewers;
- }
-
public ReviewerByEmailSet reviewersByEmail() {
if (reviewersByEmail == null) {
if (!lazyLoad) {
diff --git a/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java b/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
index 40a3a07..c6bcd60 100644
--- a/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
@@ -73,7 +73,6 @@
return false;
}
- ChangeNotes notes = notesFactory.createFromIndexedChange(change);
Optional<ProjectState> projectState = projectCache.get(cd.project());
if (!projectState.isPresent()) {
logger.atFine().log("Filter out change %s of non-existing project %s", cd, cd.project());
@@ -92,7 +91,7 @@
.filter(u -> u instanceof SingleGroupUser || u instanceof InternalUser)
.orElseGet(anonymousUserProvider::get));
try {
- withUser.indexedChange(cd, notes).check(ChangePermission.READ);
+ withUser.change(cd).check(ChangePermission.READ);
} catch (PermissionBackendException e) {
Throwable cause = e.getCause();
if (cause instanceof RepositoryNotFoundException) {
diff --git a/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java b/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
index 5b7245d..42032f7 100644
--- a/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
+++ b/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.restapi.change;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.server.CommentsUtil.setCommentCommitId;
import com.google.common.base.Strings;
@@ -73,6 +74,9 @@
throw new BadRequestException("path must be non-empty");
} else if (in.message == null || in.message.trim().isEmpty()) {
throw new BadRequestException("message must be non-empty");
+ } else if (in.path.equals(PATCHSET_LEVEL)
+ && (in.side != null || in.range != null || in.line != null)) {
+ throw new BadRequestException("patchset-level comments can't have side, range, or line");
} else if (in.line != null && in.line < 0) {
throw new BadRequestException("line must be >= 0");
} else if (in.line != null && in.range != null && in.line != in.range.endLine) {
diff --git a/java/com/google/gerrit/server/restapi/change/ListChangeComments.java b/java/com/google/gerrit/server/restapi/change/ListChangeComments.java
index e544509..409b0d5 100644
--- a/java/com/google/gerrit/server/restapi/change/ListChangeComments.java
+++ b/java/com/google/gerrit/server/restapi/change/ListChangeComments.java
@@ -73,7 +73,7 @@
throws PermissionBackendException {
ImmutableList<CommentInfo> commentInfos = getCommentFormatter().formatAsList(comments);
List<ChangeMessage> changeMessages = changeMessagesUtil.byChange(rsrc.getNotes());
- CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages, true);
return commentInfos;
}
@@ -83,7 +83,7 @@
List<CommentInfo> commentInfos =
commentInfosMap.values().stream().flatMap(List::stream).collect(toList());
List<ChangeMessage> changeMessages = changeMessagesUtil.byChange(rsrc.getNotes());
- CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages, true);
return commentInfosMap;
}
diff --git a/java/com/google/gerrit/server/restapi/change/ListChangeRobotComments.java b/java/com/google/gerrit/server/restapi/change/ListChangeRobotComments.java
index 0ed7d60..d841183 100644
--- a/java/com/google/gerrit/server/restapi/change/ListChangeRobotComments.java
+++ b/java/com/google/gerrit/server/restapi/change/ListChangeRobotComments.java
@@ -63,7 +63,7 @@
List<RobotCommentInfo> commentInfos =
robotCommentsMap.values().stream().flatMap(List::stream).collect(toList());
List<ChangeMessage> changeMessages = changeMessagesUtil.byChange(rsrc.getNotes());
- CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages, false);
return Response.ok(robotCommentsMap);
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/ListRobotComments.java b/java/com/google/gerrit/server/restapi/change/ListRobotComments.java
index 742eaca..25f4005 100644
--- a/java/com/google/gerrit/server/restapi/change/ListRobotComments.java
+++ b/java/com/google/gerrit/server/restapi/change/ListRobotComments.java
@@ -64,7 +64,7 @@
Iterable<RobotComment> comments, RevisionResource rsrc) throws PermissionBackendException {
ImmutableList<RobotCommentInfo> commentInfos = getCommentFormatter().formatAsList(comments);
List<ChangeMessage> changeMessages = changeMessagesUtil.byChange(rsrc.getNotes());
- CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages, false);
return commentInfos;
}
@@ -74,7 +74,7 @@
List<RobotCommentInfo> commentInfos =
commentInfosMap.values().stream().flatMap(List::stream).collect(toList());
List<ChangeMessage> changeMessages = changeMessagesUtil.byChange(rsrc.getNotes());
- CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(commentInfos, changeMessages, false);
return commentInfosMap;
}
diff --git a/java/com/google/gerrit/server/restapi/change/PostReview.java b/java/com/google/gerrit/server/restapi/change/PostReview.java
index 7008bb9..1e2e644 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReview.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReview.java
@@ -17,6 +17,7 @@
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.server.CommentsUtil.setCommentCommitId;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static com.google.gerrit.server.permissions.LabelPermission.ForUser.ON_BEHALF_OF;
@@ -606,6 +607,7 @@
ensureLineIsNonNegative(comment.line, path);
ensureCommentNotOnMagicFilesOfAutoMerge(path, comment);
ensureRangeIsValid(path, comment.range);
+ ensureValidPatchsetLevelComment(path, comment);
}
}
}
@@ -644,6 +646,14 @@
}
}
+ private static <T extends CommentInput> void ensureValidPatchsetLevelComment(
+ String path, T comment) throws BadRequestException {
+ if (path.equals(PATCHSET_LEVEL)
+ && (comment.side != null || comment.range != null || comment.line != null)) {
+ throw new BadRequestException("Patchset-level comments can't have side, range, or line");
+ }
+ }
+
private void checkRobotComments(
RevisionResource revision, Map<String, List<RobotCommentInput>> in)
throws BadRequestException, PatchListNotAvailableException {
@@ -703,7 +713,7 @@
ensureReplacementsArePresent(commentPath, fixReplacementInfos);
for (FixReplacementInfo fixReplacementInfo : fixReplacementInfos) {
- ensureReplacementPathIsSet(commentPath, fixReplacementInfo.path);
+ ensureReplacementPathIsSetAndNotPatchsetLevel(commentPath, fixReplacementInfo.path);
ensureRangeIsSet(commentPath, fixReplacementInfo.range);
ensureRangeIsValid(commentPath, fixReplacementInfo.range);
ensureReplacementStringIsSet(commentPath, fixReplacementInfo.replacement);
@@ -727,14 +737,20 @@
}
}
- private static void ensureReplacementPathIsSet(String commentPath, String replacementPath)
- throws BadRequestException {
+ private static void ensureReplacementPathIsSetAndNotPatchsetLevel(
+ String commentPath, String replacementPath) throws BadRequestException {
if (replacementPath == null) {
throw new BadRequestException(
String.format(
"A file path must be given for the replacement of the robot comment on %s",
commentPath));
}
+ if (replacementPath.equals(PATCHSET_LEVEL)) {
+ throw new BadRequestException(
+ String.format(
+ "A file path must not be %s for the replacement of the robot comment on %s",
+ PATCHSET_LEVEL, commentPath));
+ }
}
private static void ensureRangeIsSet(String commentPath, Range range) throws BadRequestException {
diff --git a/java/com/google/gerrit/server/restapi/change/PutDraftComment.java b/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
index 63cd7a3..ea58365 100644
--- a/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
+++ b/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.restapi.change;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.server.CommentsUtil.setCommentCommitId;
import com.google.gerrit.entities.Comment;
@@ -79,6 +80,9 @@
throw new BadRequestException("id must match URL");
} else if (in.line != null && in.line < 0) {
throw new BadRequestException("line must be >= 0");
+ } else if (in.path.equals(PATCHSET_LEVEL)
+ && (in.side != null || in.range != null || in.line != null)) {
+ throw new BadRequestException("patchset-level comments can't have side, range, or line");
} else if (in.line != null && in.range != null && in.line != in.range.endLine) {
throw new BadRequestException("range endLine must be on the same line as the comment");
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
index 83b0262..8185281 100644
--- a/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
@@ -19,9 +19,9 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.DefaultPreferencesCache;
+import com.google.gerrit.server.config.PreferencesParserUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -41,7 +41,7 @@
public Response<DiffPreferencesInfo> apply(ConfigResource configResource)
throws BadRequestException, ResourceConflictException, IOException, ConfigInvalidException {
return Response.ok(
- StoredPreferences.parseDiffPreferences(
+ PreferencesParserUtil.parseDiffPreferences(
defaultPreferenceCache.get().asConfig(), null, null));
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java b/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
index 95fc10e..bb9e483 100644
--- a/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
@@ -19,9 +19,9 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.DefaultPreferencesCache;
+import com.google.gerrit.server.config.PreferencesParserUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -40,7 +40,7 @@
public Response<EditPreferencesInfo> apply(ConfigResource configResource)
throws BadRequestException, ResourceConflictException, IOException, ConfigInvalidException {
return Response.ok(
- StoredPreferences.parseEditPreferences(
+ PreferencesParserUtil.parseEditPreferences(
defaultPreferenceCache.get().asConfig(), null, null));
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetPreferences.java b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
index 8a28d55..288055b 100644
--- a/java/com/google/gerrit/server/restapi/config/GetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
@@ -17,9 +17,9 @@
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.DefaultPreferencesCache;
+import com.google.gerrit.server.config.PreferencesParserUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -38,7 +38,7 @@
public Response<GeneralPreferencesInfo> apply(ConfigResource rsrc)
throws IOException, ConfigInvalidException {
return Response.ok(
- StoredPreferences.parseGeneralPreferences(
+ PreferencesParserUtil.parseGeneralPreferences(
defaultPreferenceCache.get().asConfig(), null, null));
}
}
diff --git a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
index 33c3584..edc3725 100644
--- a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
+++ b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
@@ -17,6 +17,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.submit.CommitMergeStatus.EMPTY_COMMIT;
import static com.google.gerrit.server.submit.CommitMergeStatus.SKIPPED_IDENTICAL_TREE;
+import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.BooleanProjectConfig;
@@ -62,20 +63,42 @@
} catch (IOException | StorageException e) {
throw new StorageException("Commit sorting failed", e);
}
- List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
- boolean first = true;
+ // We cannot rebase merge commits. This is why we integrate merge changes into the target branch
+ // the same way as if MERGE_IF_NECESSARY was the submit strategy. This means if needed we create
+ // a merge commit that integrates the merge change into the target branch.
+ // If we integrate a change series that consists out of a normal change and a merge change,
+ // where the merge change depends on the normal change, we must skip rebasing the normal change,
+ // because it already gets integrated by merging the merge change. If the rebasing of the normal
+ // change is not skipped, it would appear twice in the history after the submit is done (once
+ // through its rebased commit, and once through its original commit which is a parent of the
+ // merge change that was merged into the target branch. To skip the rebasing of the normal
+ // change, we call MergeUtil#reduceToMinimalMerge, as it excludes commits which will be
+ // implicitly integrated by merging the series. Then we use the MergeIfNecessaryOp to integrate
+ // the whole series.
+ // If on the other hand, we integrate a change series that consists out of a merge change and a
+ // normal change, where the normal change depends on the merge change, we can first integrate
+ // the merge change by a merge and then integrate the normal change by a rebase. In this case we
+ // do not want to call MergeUtil#reduceToMinimalMerge as we are not intending to integrate the
+ // whole series by a merge, but rather do the integration of the commits one by one.
+ boolean foundNonMerge = false;
for (CodeReviewCommit c : sorted) {
if (c.getParentCount() > 1) {
- // Since there is a merge commit, sort and prune again using
- // MERGE_IF_NECESSARY semantics to avoid creating duplicate
- // commits.
- //
+ if (!foundNonMerge) {
+ // found a merge change, but it doesn't depend on a normal change, this means we are not
+ // required to merge the whole series at once
+ continue;
+ }
+ // found a merge commit that depends on a normal change, this means we are required to merge
+ // the whole series at once
sorted = args.mergeUtil.reduceToMinimalMerge(args.mergeSorter, sorted);
- break;
+ return sorted.stream().map(n -> new MergeIfNecessaryOp(n)).collect(toList());
}
+ foundNonMerge = true;
}
+ List<SubmitStrategyOp> ops = new ArrayList<>(sorted.size());
+ boolean first = true;
while (!sorted.isEmpty()) {
CodeReviewCommit n = sorted.remove(0);
if (first && args.mergeTip.getInitialTip() == null) {
@@ -87,7 +110,7 @@
} else if (n.getParentCount() == 1) {
ops.add(new RebaseOneOp(n));
} else {
- ops.add(new RebaseMultipleParentsOp(n));
+ ops.add(new MergeIfNecessaryOp(n));
}
first = false;
}
@@ -254,8 +277,8 @@
}
}
- private class RebaseMultipleParentsOp extends SubmitStrategyOp {
- private RebaseMultipleParentsOp(CodeReviewCommit toMerge) {
+ private class MergeIfNecessaryOp extends SubmitStrategyOp {
+ private MergeIfNecessaryOp(CodeReviewCommit toMerge) {
super(RebaseSubmitStrategy.this.args, toMerge);
}
diff --git a/java/com/google/gerrit/testing/TestCommentHelper.java b/java/com/google/gerrit/testing/TestCommentHelper.java
index 5ce6d13..bd859db 100644
--- a/java/com/google/gerrit/testing/TestCommentHelper.java
+++ b/java/com/google/gerrit/testing/TestCommentHelper.java
@@ -26,6 +26,7 @@
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.FixSuggestionInfo;
+import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.inject.Inject;
import java.util.Arrays;
import java.util.Collection;
@@ -116,7 +117,6 @@
RobotCommentInput in = new RobotCommentInput();
in.robotId = "happyRobot";
in.robotRunId = "1";
- in.line = 1;
in.message = "nit: trailing whitespace";
in.path = path;
return in;
@@ -144,6 +144,7 @@
reviewInput.robotComments =
Collections.singletonMap(robotCommentInput.path, ImmutableList.of(robotCommentInput));
reviewInput.message = message;
+ reviewInput.tag = ChangeMessagesUtil.AUTOGENERATED_TAG_PREFIX;
gApi.changes().id(targetChangeId).current().review(reviewInput);
}
}
diff --git a/java/com/google/gerrit/truth/MapSubject.java b/java/com/google/gerrit/truth/MapSubject.java
index 8217920..95a0e0c 100644
--- a/java/com/google/gerrit/truth/MapSubject.java
+++ b/java/com/google/gerrit/truth/MapSubject.java
@@ -1,18 +1,16 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
package com.google.gerrit.truth;
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 5c786a5..82a19d4 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -4382,6 +4382,7 @@
.message("Modify rules.pl")
.create();
}
+ projectCache.evict(project);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/change/RevertIT.java b/javatests/com/google/gerrit/acceptance/api/change/RevertIT.java
index 24d08db..0ac7e20 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/RevertIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/RevertIT.java
@@ -1283,6 +1283,7 @@
.message("Modify rules.pl")
.create();
}
+ projectCache.evict(project);
}
private List<ChangeApi> getChangeApis(RevertSubmissionInfo revertSubmissionInfo)
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
index dab2d00..a9afcbc 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitTypeRuleIT.java
@@ -106,6 +106,7 @@
r.rule = rule;
r.commit(md);
}
+ projectCache.evict(project);
}
private static final String SUBMIT_TYPE_FROM_SUBJECT =
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/GetBlameIT.java b/javatests/com/google/gerrit/acceptance/api/revision/GetBlameIT.java
index 8dfebad..62140ed 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/GetBlameIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/GetBlameIT.java
@@ -15,6 +15,7 @@
package com.google.gerrit.acceptance.api.revision;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
@@ -35,6 +36,16 @@
}
@Test
+ public void forPatchsetLevelFile() throws Exception {
+ PushOneCommit.Result r = createChange("Test Change", "foo.txt", "FOO");
+ List<BlameInfo> blameInfos =
+ gApi.changes().id(r.getChangeId()).current().file(PATCHSET_LEVEL).blameRequest().get();
+
+ // File doesn't exist in commit.
+ assertThat(blameInfos).isEmpty();
+ }
+
+ @Test
public void forNonExistingFileFromBase() throws Exception {
PushOneCommit.Result r = createChange("Test Change", "foo.txt", "FOO");
List<BlameInfo> blameInfos =
@@ -51,6 +62,22 @@
}
@Test
+ public void forPatchsetLevelFileFromBase() throws Exception {
+ PushOneCommit.Result r = createChange("Test Change", "foo.txt", "FOO");
+ List<BlameInfo> blameInfos =
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .file(PATCHSET_LEVEL)
+ .blameRequest()
+ .forBase(true)
+ .get();
+
+ // File doesn't exist in base commit.
+ assertThat(blameInfos).isEmpty();
+ }
+
+ @Test
public void forNewlyAddedFile() throws Exception {
PushOneCommit.Result r = createChange("Test Change", "foo.txt", "FOO");
List<BlameInfo> blameInfos =
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index 717d3cc..5684b1f 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.TruthJUnit.assume;
import static com.google.gerrit.entities.Patch.COMMIT_MSG;
import static com.google.gerrit.entities.Patch.MERGE_LIST;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.extensions.common.testing.DiffInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.FileInfoSubject.assertThat;
import static com.google.gerrit.git.ObjectIds.abbreviateName;
@@ -121,6 +122,24 @@
}
@Test
+ public void patchsetLevelFileDiffIsEmpty() throws Exception {
+ PushOneCommit.Result result = createChange();
+ DiffInfo diffForPatchsetLevelFile =
+ gApi.changes()
+ .id(result.getChangeId())
+ .revision(result.getCommit().name())
+ .file(PATCHSET_LEVEL)
+ .diff();
+ // This behavior is the same as the behavior for non-existent files.
+ assertThat(diffForPatchsetLevelFile).binary().isNull();
+ assertThat(diffForPatchsetLevelFile).content().isEmpty();
+ assertThat(diffForPatchsetLevelFile).diffHeader().isNull();
+ assertThat(diffForPatchsetLevelFile).metaA().isNull();
+ assertThat(diffForPatchsetLevelFile).metaB().isNull();
+ assertThat(diffForPatchsetLevelFile).webLinks().isNull();
+ }
+
+ @Test
public void deletedFileIsIncludedInDiff() throws Exception {
gApi.changes().id(changeId).edit().deleteFile(FILE_NAME);
gApi.changes().id(changeId).edit().publish();
@@ -353,6 +372,31 @@
}
@Test
+ public void copiedFileDetectedIfOriginalFileIsRenamedInDiff() throws Exception {
+ /*
+ * Copies are detected when a file is deleted and more than 1 file with the same content are
+ * added. In this case, the added file with the closest name to the original file is tagged as a
+ * rename and the remaining files are considered copies. This implementation is done by JGit in
+ * the RenameDetector component.
+ */
+ String renamedFileName = "renamed_some_file.txt";
+ String copyFileName1 = "copy1_with_different_name.txt";
+ String copyFileName2 = "copy2_with_different_name.txt";
+ gApi.changes().id(changeId).edit().modifyFile(copyFileName1, RawInputUtil.create(FILE_CONTENT));
+ gApi.changes().id(changeId).edit().modifyFile(copyFileName2, RawInputUtil.create(FILE_CONTENT));
+ gApi.changes().id(changeId).edit().renameFile(FILE_NAME, renamedFileName);
+ gApi.changes().id(changeId).edit().publish();
+
+ Map<String, FileInfo> changedFiles = gApi.changes().id(changeId).current().files();
+
+ assertThat(changedFiles.keySet())
+ .containsExactly("/COMMIT_MSG", renamedFileName, copyFileName1, copyFileName2);
+ assertThat(changedFiles.get(renamedFileName).status).isEqualTo('R');
+ assertThat(changedFiles.get(copyFileName1).status).isEqualTo('C');
+ assertThat(changedFiles.get(copyFileName2).status).isEqualTo('C');
+ }
+
+ @Test
public void addedBinaryFileIsIncludedInDiff() throws Exception {
String imageFileName = "an_image.png";
byte[] imageBytes = createRgbImage(255, 0, 0);
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 74f9134..dd13643 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -24,6 +24,7 @@
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.entities.Patch.COMMIT_MSG;
import static com.google.gerrit.entities.Patch.MERGE_LIST;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
import static com.google.gerrit.git.ObjectIds.abbreviateName;
@@ -1500,6 +1501,19 @@
}
@Test
+ public void patchsetLevelContentDoesNotExist() throws Exception {
+ PushOneCommit.Result change = createChange();
+ assertThrows(
+ ResourceNotFoundException.class,
+ () ->
+ gApi.changes()
+ .id(change.getChangeId())
+ .revision(change.getCommit().name())
+ .file(PATCHSET_LEVEL)
+ .content());
+ }
+
+ @Test
public void cannotGetContentOfDirectory() throws Exception {
Map<String, String> files = ImmutableMap.of("dir/file1.txt", "content 1");
PushOneCommit.Result result =
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
index 0b8f441..27b866b 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
import static com.google.gerrit.extensions.common.testing.DiffInfoSubject.assertThat;
import static com.google.gerrit.extensions.common.testing.EditInfoSubject.assertThat;
@@ -35,6 +36,7 @@
import com.google.gerrit.extensions.api.changes.PublishChangeEditInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput;
import com.google.gerrit.extensions.client.Comment;
+import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.ChangeType;
@@ -151,7 +153,7 @@
TestTimeUtil.resetWithClockStep(0, TimeUnit.SECONDS);
createChange();
/* Advancing the time after creating the change so that the first robot comment is not in the same timestamp as with the change creation */
- TestTimeUtil.incrementClock(5, TimeUnit.SECONDS);
+ TestTimeUtil.incrementClock(10, TimeUnit.SECONDS);
RobotCommentInput c1 = TestCommentHelper.createRobotCommentInput(FILE_NAME);
RobotCommentInput c2 = TestCommentHelper.createRobotCommentInput(FILE_NAME);
@@ -220,9 +222,9 @@
.changeMessageId;
/**
- * Upload PS message, robot message 1 & robot comment 1 all have the same timestamp. The robot
- * comment is matched to robot message 1 because the PS upload message is auto-generated and is
- * ignored in matching
+ * All change messages have the auto-generated tag. Robot comments can be linked to
+ * auto-generated messages where each comment is linked to the next nearest change message in
+ * timestamp
*/
assertThat(message1ChangeId).isEqualTo(comment1MessageId);
assertThat(message2ChangeId).isEqualTo(comment2MessageId);
@@ -267,6 +269,57 @@
}
@Test
+ public void patchsetLevelRobotCommentCanBeAddedAndRetrieved() throws Exception {
+ RobotCommentInput input = TestCommentHelper.createRobotCommentInput(PATCHSET_LEVEL);
+ testCommentHelper.addRobotComment(changeId, input);
+
+ List<RobotCommentInfo> results = getRobotComments();
+ assertThatList(results).onlyElement().path().isEqualTo(PATCHSET_LEVEL);
+ }
+
+ @Test
+ public void patchsetLevelRobotCommentCantHaveLine() throws Exception {
+ RobotCommentInput input = TestCommentHelper.createRobotCommentInput(PATCHSET_LEVEL);
+ input.line = 1;
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> testCommentHelper.addRobotComment(changeId, input));
+ assertThat(ex.getMessage()).contains("line");
+ }
+
+ @Test
+ public void patchsetLevelRobotCommentCantHaveRange() throws Exception {
+ RobotCommentInput input = TestCommentHelper.createRobotCommentInput(PATCHSET_LEVEL);
+ input.range = createRange(2, 9, 5, 10);
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> testCommentHelper.addRobotComment(changeId, input));
+ assertThat(ex.getMessage()).contains("range");
+ }
+
+ @Test
+ public void patchsetLevelRobotCommentCantHaveSide() throws Exception {
+ RobotCommentInput input = TestCommentHelper.createRobotCommentInput(PATCHSET_LEVEL);
+ input.side = Side.REVISION;
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> testCommentHelper.addRobotComment(changeId, input));
+ assertThat(ex.getMessage()).contains("side");
+ }
+
+ @Test
+ public void fixSuggestionCannotPointToPatchsetLevel() throws Exception {
+ RobotCommentInput input = TestCommentHelper.createRobotCommentInput(FILE_NAME);
+ FixReplacementInfo brokenFixReplacement = createFixReplacementInfo();
+ brokenFixReplacement.path = PATCHSET_LEVEL;
+ input.fixSuggestions = ImmutableList.of(createFixSuggestionInfo(brokenFixReplacement));
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> testCommentHelper.addRobotComment(changeId, input));
+ assertThat(ex.getMessage()).contains("file path must not be " + PATCHSET_LEVEL);
+ }
+
+ @Test
public void hugeRobotCommentIsRejected() {
int defaultSizeLimit = 1 << 20;
fixReplacementInfo.replacement = getStringFor(defaultSizeLimit + 1);
diff --git a/javatests/com/google/gerrit/acceptance/pgm/InitIT.java b/javatests/com/google/gerrit/acceptance/pgm/InitIT.java
index 4caee64..4db0177 100644
--- a/javatests/com/google/gerrit/acceptance/pgm/InitIT.java
+++ b/javatests/com/google/gerrit/acceptance/pgm/InitIT.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth8.assertThat;
import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.MustBeClosed;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.StandaloneSiteTest;
import com.google.gerrit.entities.Project;
@@ -82,27 +83,33 @@
private void setProjectsIndexLastModifiedInThePast(Path indexDir, Instant time)
throws IOException {
- for (Path path : getAllProjectsIndexFiles(indexDir).collect(Collectors.toList())) {
- FS.DETECTED.setLastModified(path, time);
+ try (Stream<Path> allprojectsIndexFiles = getAllProjectsIndexFiles(indexDir)) {
+ for (Path path : allprojectsIndexFiles.collect(Collectors.toList())) {
+ FS.DETECTED.setLastModified(path, time);
+ }
}
}
private Optional<Instant> getProjectsIndexLastModified(Path indexDir) throws IOException {
- return getAllProjectsIndexFiles(indexDir)
- .map(FS.DETECTED::lastModifiedInstant)
- .max(Comparator.comparingLong(Instant::toEpochMilli));
+ try (Stream<Path> allprojectsIndexFiles = getAllProjectsIndexFiles(indexDir)) {
+ return allprojectsIndexFiles
+ .map(FS.DETECTED::lastModifiedInstant)
+ .max(Comparator.comparingLong(Instant::toEpochMilli));
+ }
}
+ @MustBeClosed
private Stream<Path> getAllProjectsIndexFiles(Path indexDir) throws IOException {
- Optional<Path> projectsPath =
- Files.walk(indexDir, 1)
- .filter(Files::isDirectory)
- .filter(p -> p.getFileName().toString().startsWith("projects_"))
- .findFirst();
- if (!projectsPath.isPresent()) {
- return Stream.empty();
+ try (Stream<Path> stream = Files.walk(indexDir, 1)) {
+ Optional<Path> projectsPath =
+ stream
+ .filter(Files::isDirectory)
+ .filter(p -> p.getFileName().toString().startsWith("projects_"))
+ .findFirst();
+ if (!projectsPath.isPresent()) {
+ return Stream.empty();
+ }
+ return Files.walk(projectsPath.get(), 1, FileVisitOption.FOLLOW_LINKS);
}
-
- return Files.walk(projectsPath.get(), 1, FileVisitOption.FOLLOW_LINKS);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index 72db9b3..2779284 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -299,6 +299,89 @@
assertTrees(project, actual);
}
+ /**
+ * Tests the following situation:
+ *
+ * <ul>
+ * <li>1. create a change series, consisting out of a merge commit and a normal commit
+ * <li>2. before submitting the change series, another non-conflicting change gets submitted
+ * <li>3. when the change series gets submitted, Gerrit must perform a merge/rebase/cherry-pick
+ * </ul>
+ */
+ @Test
+ public void submitChangeSeriesWithMergeCommitThatIsBasedOnOldTip() throws Throwable {
+ RevCommit initialHead = projectOperations.project(project).getHead("master");
+
+ // create a commit which will become the first parent of a merge commit
+ PushOneCommit.Result parent1 =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ "parent 2",
+ ImmutableMap.of("foo", "foo-2", "bar", "bar-2"))
+ .to("refs/heads/master");
+
+ // reset the testRepo in order to create a sibling of parent1
+ testRepo.reset(initialHead);
+
+ // create a stable branch that we can merge back into master later
+ BranchInput in = new BranchInput();
+ in.revision = initialHead.getName();
+ gApi.projects().name(project.get()).branch("refs/heads/stable").create(in);
+
+ // create one commit in the stable branch, which will become the second parent of the merge
+ // commit
+ PushOneCommit.Result parent2 =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ "parent 1",
+ ImmutableMap.of("foo", "foo-1", "bar", "bar-1"))
+ .to("refs/heads/stable");
+
+ // create a merge change that merges the stable branch back into master
+ testRepo.reset(parent1.getCommit());
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1.getCommit(), parent2.getCommit()));
+ PushOneCommit.Result mergeChange = m.to("refs/for/master");
+ mergeChange.assertOkStatus();
+
+ // approve the merge change so that it becomes submittable
+ approve(mergeChange.getChangeId());
+
+ // create a successor change that depends on the merge change
+ PushOneCommit.Result successorChange = createChange("refs/for/master");
+
+ // simulate another developer submitting a change in the meantime (non-conflicting sibling
+ // commit of the merge commit), this means when the change series gets submitted Gerrit must
+ // perform a merge/rebase/cherry-pick now
+ testRepo.reset(parent1.getCommit());
+ submit(createChange("Other Change", "x.txt", "x content").getChangeId());
+
+ // submit the change series
+ if (getSubmitType() != SubmitType.FAST_FORWARD_ONLY) {
+ submit(successorChange.getChangeId());
+ } else {
+ submitWithConflict(
+ successorChange.getChangeId(),
+ "Failed to submit 2 changes due to the following problems:\n"
+ + "Change "
+ + mergeChange.getChange().getId()
+ + ": Project policy "
+ + "requires all submissions to be a fast-forward. Please "
+ + "rebase the change locally and upload again for review.\n"
+ + "Change "
+ + successorChange.getChange().getId()
+ + ": Project policy "
+ + "requires all submissions to be a fast-forward. Please "
+ + "rebase the change locally and upload again for review.");
+ }
+ }
+
@Test
public void submitNoPermission() throws Throwable {
// create project where submit is blocked
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
index ecd4025..4fac821 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -18,7 +18,9 @@
import static com.google.common.truth.Truth8.assertThat;
import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static com.google.gerrit.truth.MapSubject.assertThatMap;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
@@ -176,6 +178,189 @@
}
@Test
+ public void patchsetLevelCommentCanBeAddedAndRetrieved() throws Exception {
+ PushOneCommit.Result result = createChange();
+ String changeId = result.getChangeId();
+ String ps1 = result.getCommit().name();
+
+ CommentInput comment = newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ addComments(changeId, ps1, comment);
+
+ Map<String, List<CommentInfo>> results = getPublishedComments(changeId, ps1);
+ assertThatMap(results).keys().containsExactly(PATCHSET_LEVEL);
+ }
+
+ @Test
+ public void deletePatchsetLevelComment() throws Exception {
+ requestScopeOperations.setApiUser(admin.id());
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ String commentMessage = "to be deleted";
+ CommentInput comment = newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, commentMessage);
+ addComments(changeId, revId, comment);
+
+ Map<String, List<CommentInfo>> results = getPublishedComments(changeId, revId);
+ CommentInfo oldComment = Iterables.getOnlyElement(results.get(PATCHSET_LEVEL));
+
+ DeleteCommentInput input = new DeleteCommentInput("reason");
+ gApi.changes().id(changeId).revision(revId).comment(oldComment.id).delete(input);
+ CommentInfo updatedComment =
+ Iterables.getOnlyElement(getPublishedComments(changeId, revId).get(PATCHSET_LEVEL));
+
+ assertThat(updatedComment.message).doesNotContain(commentMessage);
+ }
+
+ @Test
+ public void patchsetLevelCommentCantHaveLine() throws Exception {
+ PushOneCommit.Result result = createChange();
+ String changeId = result.getChangeId();
+ String ps1 = result.getCommit().name();
+
+ CommentInput input = newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ input.line = 1;
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addComments(changeId, ps1, input));
+ assertThat(ex.getMessage()).contains("line");
+ }
+
+ @Test
+ public void patchsetLevelCommentCantHaveRange() throws Exception {
+ PushOneCommit.Result result = createChange();
+ String changeId = result.getChangeId();
+ String ps1 = result.getCommit().name();
+
+ CommentInput input = newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ input.range = createLineRange(1, 3);
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addComments(changeId, ps1, input));
+ assertThat(ex.getMessage()).contains("range");
+ }
+
+ @Test
+ public void patchsetLevelCommentCantHaveSide() throws Exception {
+ PushOneCommit.Result result = createChange();
+ String changeId = result.getChangeId();
+ String ps1 = result.getCommit().name();
+
+ CommentInput input = newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ input.side = Side.REVISION;
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addComments(changeId, ps1, input));
+ assertThat(ex.getMessage()).contains("side");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCanBeAddedAndRetrieved() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ addDraft(changeId, revId, comment);
+ Map<String, List<CommentInfo>> results = getDraftComments(changeId, revId);
+ assertThatMap(results).keys().containsExactly(PATCHSET_LEVEL);
+ }
+
+ @Test
+ public void deletePatchsetLevelDraft() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput draft = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment 1");
+ CommentInfo returned = addDraft(changeId, revId, draft);
+ deleteDraft(changeId, revId, returned.id);
+ Map<String, List<CommentInfo>> drafts = getDraftComments(changeId, revId);
+ assertThat(drafts).isEmpty();
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantHaveLine() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ comment.line = 1;
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addDraft(changeId, revId, comment));
+ assertThat(ex.getMessage()).contains("line");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantHaveRange() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ comment.range = createLineRange(1, 3);
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addDraft(changeId, revId, comment));
+ assertThat(ex.getMessage()).contains("range");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantHaveSide() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ comment.side = Side.REVISION;
+ BadRequestException ex =
+ assertThrows(BadRequestException.class, () -> addDraft(changeId, revId, comment));
+ assertThat(ex.getMessage()).contains("range");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantBeUpdatedToHaveLine() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ addDraft(changeId, revId, comment);
+ Map<String, List<CommentInfo>> results = getDraftComments(changeId, revId);
+ DraftInput update = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ update.id = Iterables.getOnlyElement(results.get(PATCHSET_LEVEL)).id;
+ update.line = 1;
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> updateDraft(changeId, revId, update, update.id));
+ assertThat(ex.getMessage()).contains("line");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantBeUpdatedToHaveRange() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ addDraft(changeId, revId, comment);
+ Map<String, List<CommentInfo>> results = getDraftComments(changeId, revId);
+ DraftInput update = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ update.id = Iterables.getOnlyElement(results.get(PATCHSET_LEVEL)).id;
+ update.range = createLineRange(1, 3);
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> updateDraft(changeId, revId, update, update.id));
+ assertThat(ex.getMessage()).contains("range");
+ }
+
+ @Test
+ public void patchsetLevelDraftCommentCantBeUpdatedToHaveSide() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ DraftInput comment = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ addDraft(changeId, revId, comment);
+ Map<String, List<CommentInfo>> results = getDraftComments(changeId, revId);
+ DraftInput update = newDraftWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ update.id = Iterables.getOnlyElement(results.get(PATCHSET_LEVEL)).id;
+ update.side = Side.REVISION;
+ BadRequestException ex =
+ assertThrows(
+ BadRequestException.class, () -> updateDraft(changeId, revId, update, update.id));
+ assertThat(ex.getMessage()).contains("side");
+ }
+
+ @Test
public void postCommentWithReply() throws Exception {
for (Integer line : lines) {
String file = "file";
@@ -1083,7 +1268,7 @@
addComments(changeId, ps4, c7, c8);
// 11th commit: Add (c9) to PS2.
- CommentInput c9 = newComment("b.txt", "comment 9");
+ CommentInput c9 = newCommentWithOnlyMandatoryFields("b.txt", "comment 9");
addComments(changeId, ps2, c9);
List<CommentInfo> commentsBeforeDelete = getChangeSortedComments(id.get());
@@ -1340,6 +1525,11 @@
return newComment(file, Side.REVISION, 0, message, false);
}
+ private static CommentInput newCommentWithOnlyMandatoryFields(String path, String message) {
+ CommentInput c = new CommentInput();
+ return populate(c, path, null, null, null, null, message, false);
+ }
+
private static CommentInput newComment(
String path, Side side, int line, String message, Boolean unresolved) {
CommentInput c = new CommentInput();
@@ -1367,19 +1557,24 @@
return populate(d, path, Side.PARENT, parent, line, message, false);
}
+ private DraftInput newDraftWithOnlyMandatoryFields(String path, String message) {
+ DraftInput d = new DraftInput();
+ return populate(d, path, null, null, null, null, message, false);
+ }
+
private static <C extends Comment> C populate(
C c,
String path,
Side side,
Integer parent,
- int line,
+ Integer line,
Comment.Range range,
String message,
Boolean unresolved) {
c.path = path;
c.side = side;
c.parent = parent;
- c.line = line != 0 ? line : null;
+ c.line = line != null && line != 0 ? line : null;
c.message = message;
c.unresolved = unresolved;
if (range != null) {
diff --git a/javatests/com/google/gerrit/acceptance/server/permissions/PermissionBackendIT.java b/javatests/com/google/gerrit/acceptance/server/permissions/PermissionBackendIT.java
new file mode 100644
index 0000000..2aab159
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/server/permissions/PermissionBackendIT.java
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.server.permissions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.inject.Inject;
+import org.junit.Test;
+
+/** Asserts behavior on {@link PermissionBackend} using a fully-started Gerrit. */
+public class PermissionBackendIT extends AbstractDaemonTest {
+ @Inject PermissionBackend pb;
+ @Inject ChangeNotes.Factory changeNotesFactory;
+
+ @Test
+ public void changeDataFromIndex_canCheckReviewerState() throws Exception {
+ Change.Id changeId = createChange().getChange().getId();
+ gApi.changes().id(changeId.get()).setPrivate(true);
+ gApi.changes().id(changeId.get()).addReviewer(user.email());
+
+ ChangeData changeData =
+ Iterables.getOnlyElement(queryProvider.get().byLegacyChangeId(changeId));
+ boolean reviewerCanSee =
+ pb.absentUser(user.id()).change(changeData).test(ChangePermission.READ);
+ assertThat(reviewerCanSee).isTrue();
+ }
+
+ @Test
+ public void changeDataFromNoteDb_canCheckReviewerState() throws Exception {
+ Change.Id changeId = createChange().getChange().getId();
+ gApi.changes().id(changeId.get()).setPrivate(true);
+ gApi.changes().id(changeId.get()).addReviewer(user.email());
+
+ ChangeNotes notes = changeNotesFactory.create(project, changeId);
+ ChangeData changeData = changeDataFactory.create(notes);
+ boolean reviewerCanSee =
+ pb.absentUser(user.id()).change(changeData).test(ChangePermission.READ);
+ assertThat(reviewerCanSee).isTrue();
+ }
+
+ @Test
+ public void changeNotes_canCheckReviewerState() throws Exception {
+ Change.Id changeId = createChange().getChange().getId();
+ gApi.changes().id(changeId.get()).setPrivate(true);
+ gApi.changes().id(changeId.get()).addReviewer(user.email());
+
+ ChangeNotes notes = changeNotesFactory.create(project, changeId);
+ boolean reviewerCanSee = pb.absentUser(user.id()).change(notes).test(ChangePermission.READ);
+ assertThat(reviewerCanSee).isTrue();
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java b/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
index e5432d1..18ae6c4 100644
--- a/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
@@ -29,7 +29,6 @@
import java.util.Collection;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Repository;
-import org.junit.Before;
import org.junit.Test;
/**
@@ -44,14 +43,6 @@
@Inject private ProjectOperations projectOperations;
@Inject private SubmitRuleEvaluator.Factory evaluatorFactory;
- @Before
- public void setUp() {
- // We don't want caches to interfere with our tests. If we didn't, the cache would take
- // precedence over the index, which would never be called.
- baseConfig.setString("cache", "changes", "memoryLimit", "0");
- baseConfig.setString("cache", "projects", "memoryLimit", "0");
- }
-
@Test
public void testUnresolvedCommentsCountPredicate() throws Exception {
modifySubmitRules("gerrit:unresolved_comments_count(0)");
@@ -119,5 +110,6 @@
.message("Modify rules.pl")
.create();
}
+ projectCache.evict(project);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/SetReviewersIT.java b/javatests/com/google/gerrit/acceptance/ssh/SetReviewersIT.java
index 5a31bfd..58c2517 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/SetReviewersIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/SetReviewersIT.java
@@ -65,7 +65,7 @@
session.exec(
String.format("gerrit set-reviewers -%s %s %s", add ? "a" : "r", user.email(), id));
session.assertSuccess();
- ImmutableSet<Account.Id> reviewers = change.getChange().getReviewers().all();
+ ImmutableSet<Account.Id> reviewers = change.getChange().reviewers().all();
if (add) {
assertThat(reviewers).contains(user.id());
} else {
diff --git a/javatests/com/google/gerrit/entities/PatchTest.java b/javatests/com/google/gerrit/entities/PatchTest.java
index 9f906a9..dce1b3e 100644
--- a/javatests/com/google/gerrit/entities/PatchTest.java
+++ b/javatests/com/google/gerrit/entities/PatchTest.java
@@ -24,6 +24,7 @@
public void isMagic() {
assertThat(Patch.isMagic("/COMMIT_MSG")).isTrue();
assertThat(Patch.isMagic("/MERGE_LIST")).isTrue();
+ assertThat(Patch.isMagic("/PATCHSET_LEVEL")).isTrue();
assertThat(Patch.isMagic("/COMMIT_MSG/")).isFalse();
assertThat(Patch.isMagic("COMMIT_MSG")).isFalse();
diff --git a/javatests/com/google/gerrit/server/patch/PatchListTest.java b/javatests/com/google/gerrit/server/patch/PatchListTest.java
index e224191a..56adefa 100644
--- a/javatests/com/google/gerrit/server/patch/PatchListTest.java
+++ b/javatests/com/google/gerrit/server/patch/PatchListTest.java
@@ -26,16 +26,30 @@
import org.junit.Test;
public class PatchListTest {
+
@Test
public void fileOrder() {
String[] names = {
- "zzz", "def/g", "/!xxx", "abc", Patch.MERGE_LIST, "qrx", Patch.COMMIT_MSG,
+ "zzz",
+ "def/g",
+ "/!xxx",
+ "abc",
+ Patch.MERGE_LIST,
+ "qrx",
+ Patch.COMMIT_MSG,
+ Patch.PATCHSET_LEVEL
};
String[] want = {
- Patch.COMMIT_MSG, Patch.MERGE_LIST, "/!xxx", "abc", "def/g", "qrx", "zzz",
+ Patch.COMMIT_MSG,
+ Patch.MERGE_LIST,
+ Patch.PATCHSET_LEVEL,
+ "/!xxx",
+ "abc",
+ "def/g",
+ "qrx",
+ "zzz",
};
-
- Arrays.sort(names, 0, names.length, PatchList::comparePaths);
+ Arrays.sort(names, 0, names.length, PatchList.FILE_PATH_CMP);
assertThat(names).isEqualTo(want);
}
@@ -48,7 +62,7 @@
Patch.COMMIT_MSG, "/!xxx", "abc", "def/g", "qrx", "zzz",
};
- Arrays.sort(names, 0, names.length, PatchList::comparePaths);
+ Arrays.sort(names, 0, names.length, PatchList.FILE_PATH_CMP);
assertThat(names).isEqualTo(want);
}
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 1aa0f35..11e98c6 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -3039,6 +3039,7 @@
List<ChangeInfo> result = newQuery("attention:" + user2Id.toString()).get();
assertThat(result).hasSize(1);
ChangeInfo changeInfo = Iterables.getOnlyElement(result);
+ assertThat(changeInfo.attentionSet).isNotNull();
assertThat(changeInfo.attentionSet.keySet()).containsExactly(userId.get(), user2Id.get());
assertThat(changeInfo.attentionSet.get(userId.get()).reason).isEqualTo("reason 1");
assertThat(changeInfo.attentionSet.get(user2Id.get()).reason).isEqualTo("reason 2");
diff --git a/javatests/com/google/gerrit/server/restapi/change/ListChangeCommentsTest.java b/javatests/com/google/gerrit/server/restapi/change/ListChangeCommentsTest.java
index 9f34377..5a28404 100644
--- a/javatests/com/google/gerrit/server/restapi/change/ListChangeCommentsTest.java
+++ b/javatests/com/google/gerrit/server/restapi/change/ListChangeCommentsTest.java
@@ -1,18 +1,16 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
package com.google.gerrit.server.restapi.change;
@@ -22,6 +20,7 @@
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.extensions.common.CommentInfo;
+import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.CommentsUtil;
import java.sql.Timestamp;
import org.junit.Test;
@@ -33,27 +32,38 @@
@Test
public void commentsLinkedToChangeMessages() {
+ /**
+ * Human comments should not be linked to auto-generated messages. A comment is linked to the
+ * nearest next change message in timestamp
+ */
CommentInfo c1 = getNewCommentInfo("c1", Timestamp.valueOf("2018-01-01 09:01:00"));
CommentInfo c2 = getNewCommentInfo("c2", Timestamp.valueOf("2018-01-01 09:01:15"));
CommentInfo c3 = getNewCommentInfo("c3", Timestamp.valueOf("2018-01-01 09:01:25"));
ChangeMessage cm1 =
- getNewChangeMessage("cm1key", "cm1", Timestamp.valueOf("2018-01-01 00:00:00"));
+ getNewChangeMessage("cm1key", "cm1", Timestamp.valueOf("2018-01-01 00:00:00"), null);
+ ChangeMessage cmIgnore =
+ getNewChangeMessage(
+ "cm2key",
+ "cm2",
+ Timestamp.valueOf("2018-01-01 09:01:15"),
+ ChangeMessagesUtil.AUTOGENERATED_TAG_PREFIX);
ChangeMessage cm2 =
- getNewChangeMessage("cm2key", "cm2", Timestamp.valueOf("2018-01-01 09:01:15"));
+ getNewChangeMessage("cm2key", "cm2", Timestamp.valueOf("2018-01-01 09:01:16"), null);
ChangeMessage cm3 =
- getNewChangeMessage("cm3key", "cm3", Timestamp.valueOf("2018-01-01 09:01:27"));
+ getNewChangeMessage("cm3key", "cm3", Timestamp.valueOf("2018-01-01 09:01:27"), null);
assertThat(c1.changeMessageId).isNull();
assertThat(c2.changeMessageId).isNull();
assertThat(c3.changeMessageId).isNull();
ImmutableList<CommentInfo> comments = ImmutableList.of(c1, c2, c3);
- ImmutableList<ChangeMessage> changeMessages = ImmutableList.of(cm1, cm2, cm3);
+ ImmutableList<ChangeMessage> changeMessages = ImmutableList.of(cm1, cmIgnore, cm2, cm3);
- CommentsUtil.linkCommentsToChangeMessages(comments, changeMessages);
+ CommentsUtil.linkCommentsToChangeMessages(comments, changeMessages, true);
assertThat(c1.changeMessageId).isEqualTo(changeMessageKey(cm2));
+ /** comment 2 ignored the auto-generated change message */
assertThat(c2.changeMessageId).isEqualTo(changeMessageKey(cm2));
assertThat(c3.changeMessageId).isEqualTo(changeMessageKey(cm3));
}
@@ -65,10 +75,12 @@
return c;
}
- private static ChangeMessage getNewChangeMessage(String id, String message, Timestamp ts) {
+ private static ChangeMessage getNewChangeMessage(
+ String id, String message, Timestamp ts, String tag) {
ChangeMessage.Key key = ChangeMessage.key(Change.id(1), id);
ChangeMessage cm = new ChangeMessage(key, null, ts, null);
cm.setMessage(message);
+ cm.setTag(tag);
return cm;
}
diff --git a/package.json b/package.json
index 526d201..926de4e 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,10 @@
"eslint": "npm run safe_bazelisk test polygerrit-ui/app:lint_test",
"eslintfix": "npm run safe_bazelisk run polygerrit-ui/app:lint_bin -- -- --fix $(pwd)/polygerrit-ui/app",
"test-template": "./polygerrit-ui/app/run_template_test.sh",
- "polylint": "npm run safe_bazelisk test polygerrit-ui/app:polylint_test"
+ "polylint": "npm run safe_bazelisk test polygerrit-ui/app:polylint_test",
+ "test:karma:debug": "npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --browsers ChromeDev --no-single-run --testFiles",
+ "test:karma": "npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --testFiles",
+ "test:wct": "npm run test -- --test_tag_filters=wct"
},
"repository": {
"type": "git",
diff --git a/plugins/delete-project b/plugins/delete-project
index d6ad8e7..e345e6e 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit d6ad8e7de90331a317a8eaaf353f7cb7bd31d1a1
+Subproject commit e345e6e79900a72981e4ad19d37c7fbdcae4818b
diff --git a/plugins/plugin-manager b/plugins/plugin-manager
index 93d8e12..9e7b0a0 160000
--- a/plugins/plugin-manager
+++ b/plugins/plugin-manager
@@ -1 +1 @@
-Subproject commit 93d8e1248478c6b2db0a8c1080f2766406dd213d
+Subproject commit 9e7b0a086b3e4d56a3a9407d21b6648c650b8809
diff --git a/plugins/replication b/plugins/replication
index 88eeb9a..9ae2087 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 88eeb9aa1f15fcf0d891a901990efd5574fa8cf3
+Subproject commit 9ae20871646a0757979e3bef03aaf4e74af8ff73
diff --git a/polygerrit-ui/BUILD b/polygerrit-ui/BUILD
index a029df4..021ce08 100644
--- a/polygerrit-ui/BUILD
+++ b/polygerrit-ui/BUILD
@@ -1,5 +1,6 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
load("//tools/bzl:genrule2.bzl", "genrule2")
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
@@ -32,3 +33,43 @@
"@org_golang_x_tools//godoc/vfs/zipfs:go_default_library",
],
)
+
+# Define a karma+plugins binary to run karma-mocha tests.
+# Can be reused multiple time, if there are multiple karma test rules
+sh_binary(
+ name = "karma_bin",
+ srcs = ["@ui_dev_npm//:node_modules/karma/bin/karma"],
+ data = [
+ "@ui_dev_npm//@open-wc/karma-esm",
+ "@ui_dev_npm//chai",
+ "@ui_dev_npm//karma-chrome-launcher",
+ "@ui_dev_npm//karma-mocha",
+ "@ui_dev_npm//karma-mocha-reporter",
+ "@ui_dev_npm//karma/bin:karma",
+ "@ui_dev_npm//mocha",
+ ],
+)
+
+# Run all tests in one.
+# TODO(dmfilippov): allow parallel tests for karma - either on the bazel level
+# or on the karma level. For now single sh_test is enough.
+sh_test(
+ name = "karma_test",
+ size = "enormous",
+ srcs = ["karma_test.sh"],
+ args = [
+ "$(location :karma_bin)",
+ "$(location karma.conf.js)",
+ ],
+ data = [
+ "karma.conf.js",
+ ":karma_bin",
+ "//polygerrit-ui/app:test-srcs-fg",
+ ],
+ # Should not run sandboxed.
+ tags = [
+ "karma",
+ "local",
+ "manual",
+ ],
+)
diff --git a/polygerrit-ui/FE_Style_Guide.md b/polygerrit-ui/FE_Style_Guide.md
new file mode 100644
index 0000000..c9a5d9b
--- /dev/null
+++ b/polygerrit-ui/FE_Style_Guide.md
@@ -0,0 +1,263 @@
+# Gerrit JavaScript style guide
+
+Gerrit frontend follows [recommended eslint rules](https://eslint.org/docs/rules/)
+and [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html).
+Eslint is used to automate rules checking where possible. You can find exact eslint rules
+[here](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/polygerrit-ui/app/.eslintrc.js).
+
+Gerrit JavaScript code uses ES6 modules and doesn't use goog.module files.
+
+Additionally to the rules above, Gerrit frontend uses the following rules (some of them have automated checks,
+some don't):
+
+- [Use destructuring imports only](#destructuring-imports-only)
+- [Use classes and services for storing and manipulating global state](#services-for-global-state)
+- [Pass required services in the constructor for plain classes](#pass-dependencies-in-constructor)
+- [Assign required services in a HTML/Polymer element constructor](#assign-dependencies-in-html-element-constructor)
+
+## <a name="destructuring-imports-only"></a>Use destructuring imports only
+Always use destructuring import statement and specify all required names explicitly (e.g. `import {a,b,c} from '...'`)
+where possible.
+
+**Note:** Destructuring imports are not always possible with 3rd-party libraries, because a 3rd-party library
+can expose a class/function/const/etc... as a default export. In this situation you can use default import, but please
+keep consistent naming across the whole gerrit project. The best way to keep consistency is to search across our
+codebase for the same import. If you find an exact match - always use the same name for your import. If you can't
+find exact matches - find a similar import and assign appropriate/similar name for your default import. Usually the
+name should include a library name and part of the file path.
+
+You can read more about different type of imports
+[here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import).
+
+**Good:**
+```Javascript
+// Import from the module in the same project.
+import {getDisplayName, getAccount} from './user-utils.js'
+
+// The following default import is allowed only for 3rd-party libraries.
+// Please ensure, that all imports have the same name accross gerrit project (downloadImage in this example)
+import downloadImage from 'third-party-library/images/download.js'
+```
+
+**Bad:**
+```Javascript
+import * as userUtils from './user-utils.js'
+```
+
+## <a name="services-for-global-state"></a>Use classes and services for storing and manipulating global state
+
+You must use classes and services to share global state across the gerrit frontend code. Do not put a state at the
+top level of a module.
+
+It is not easy to define precise what can be a shared global state and what is not. Below are some
+examples of what can treated as a shared global state:
+
+* Information about enabled experiments
+* Information about current user
+* Information about current change
+
+**Note:**
+
+Service name must ends with a `Service` suffix.
+
+To share global state across modules in the project, do the following:
+- put the state in a class
+- add a new service to the
+[appContext](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/polygerrit-ui/app/services/app-context.js)
+- add a service initialization code to the
+[services/app-context-init.js](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/polygerrit-ui/app/services/app-context-init.js) file.
+- add a service or service-mock initialization code to the
+[embed/app-context-init.js](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/polygerrit-ui/app/embed/app-context-init.js) file.
+- recommended: add a separate service-mock for testing. Do not use the same mock for testing and for
+the shared gr-diff (i.e. in the `services/app-context-init.js`). Even if the mocks are simple and looks
+identically, keep them separate. It allows to change them independently in the future.
+
+Also see the example below if a service depends on another services.
+
+**Note 1:** Be carefull with the shared gr-diff element. If a service is not required for the shared gr-diff,
+the safest option is to provide a mock for this service in the embed/app-context-init.js file. In exceptional
+cases you can keep the service uninitialized in
+[embed/app-context-init.js](https://gerrit.googlesource.com/gerrit/+/refs/heads/master/polygerrit-ui/app/embed/app-context-init.js) file
+, but it is recommended to write a comment why mocking is not possible. In the future we can
+review/update rules regarding the shared gr-diff element.
+
+**Good:**
+```Javascript
+export class CounterService {
+ constructor() {
+ this._count = 0;
+ }
+ get count() {
+ return this._count;
+ }
+ inc() {
+ this._count++;
+ }
+}
+
+// app-context.js
+export const appContext = {
+ //...
+ mouseClickCounterService: null,
+ keypressCounterService: null,
+};
+
+// services/app-context-init.js
+export function initAppContext() {
+ //...
+ // Add the following line before the Object.defineProperties(appContext, registeredServices);
+ addService('mouseClickCounterService', () => new CounterService());
+ addService('keypressCounterService', () => new CounterService());
+ // If a service depends on other services, pass dependencies as shown below
+ // If circular dependencies exist, app-init-context tests fail with timeout or stack overflow
+ // (we are going to improve it in the future)
+ addService('analyticService', () =>
+ new CounterService(appContext.mouseClickCounterService, appContext.keypressCounterService));
+ //...
+ // This following line must remains the last one in the initAppContext
+ Object.defineProperties(appContext, registeredServices);
+}
+```
+
+**Bad:**
+```Javascript
+// module counter.js
+// Incorrect: shared state declared at the top level of the counter.js module
+let count = 0;
+export function getCount() {
+ return count;
+}
+export function incCount() {
+ count++;
+}
+```
+
+## <a name="pass-dependencies-in-constructor"></a>Pass required services in the constructor for plain classes
+
+If a class/service depends on some other service (or multiple services), the class must accept all dependencies
+as parameters in the constructor.
+
+Do not use appContext anywhere else in a class.
+
+**Note:** This rule doesn't apply for HTML/Polymer elements classes. A browser creates instances of such classes
+implicitly and calls the constructor without parameters. See
+[Assign required services in a HTML/Polymer element constructor](#assign-dependencies-in-html-element-constructor)
+
+**Good:**
+```Javascript
+export class UserService {
+ constructor(restApiService) {
+ this._restApiService = restApiService;
+ }
+ getLoggedIn() {
+ // Send request to server using this._restApiService
+ }
+}
+```
+
+**Bad:**
+```Javascript
+import {appContext} from "./app-context";
+
+export class UserService {
+ constructor() {
+ // Incorrect: you must pass all dependencies to a constructor
+ this._restApiService = appContext.restApiService;
+ }
+}
+
+export class AdminService {
+ isAdmin() {
+ // Incorrect: you must pass all dependencies to a constructor
+ return appContext.restApiService.sendRequest(...);
+ }
+}
+
+```
+
+## <a name="assign-dependencies-in-html-element-constructor"></a>Assign required services in a HTML/Polymer element constructor
+If a class is a custom HTML/Polymer element, the class must assign all required services in the constructor.
+A browser creates instances of such classes implicitly, so it is impossible to pass anything as a parameter to
+the element's class constructor.
+
+Do not use appContext anywhere except the constructor of the class.
+
+**Note for legacy elements:** If a polymer element extends a LegacyElementMixin and overrides the `created()` method,
+move all code from this method to a constructor right after the call to a `super()`
+([example](#assign-dependencies-legacy-element-example)). The `created()`
+method is [deprecated](https://polymer-library.polymer-project.org/2.0/docs/about_20#lifecycle-changes) and is called
+when a super (i.e. base) class constructor is called. If you are unsure about moving the code from the `created` method
+to the class constructor, consult with the source code:
+[`LegacyElementMixin._initializeProperties`](https://github.com/Polymer/polymer/blob/v3.4.0/lib/legacy/legacy-element-mixin.js#L318)
+and
+[`PropertiesChanged.constructor`](https://github.com/Polymer/polymer/blob/v3.4.0/lib/mixins/properties-changed.js#L177)
+
+
+
+**Good:**
+```Javascript
+import {appContext} from `.../services/app-context.js`;
+
+export class MyCustomElement extends ...{
+ constructor() {
+ super(); //This is mandatory to call parent constructor
+ this._userService = appContext.userService;
+ }
+ //...
+ _getUserName() {
+ return this._userService.activeUserName();
+ }
+}
+```
+
+**Bad:**
+```Javascript
+import {appContext} from `.../services/app-context.js`;
+
+export class MyCustomElement extends ...{
+ created() {
+ // Incorrect: assign all dependencies in the constructor
+ this._userService = appContext.userService;
+ }
+ //...
+ _getUserName() {
+ // Incorrect: use appContext outside of a constructor
+ return appContext.userService.activeUserName();
+ }
+}
+```
+
+<a name="assign-dependencies-legacy-element-example"></a>
+**Legacy element:**
+
+Before:
+```Javascript
+export class MyCustomElement extends ...LegacyElementMixin(...) {
+ constructor() {
+ super();
+ someAction();
+ }
+ created() {
+ super();
+ createdAction1();
+ createdAction2();
+ }
+}
+```
+
+After:
+```Javascript
+export class MyCustomElement extends ...LegacyElementMixin(...) {
+ constructor() {
+ super();
+ // Assign services here
+ this._userService = appContext.userService;
+ // Code from the created method - put it before existing actions in constructor
+ createdAction1();
+ createdAction2();
+ // Original constructor code
+ someAction();
+ }
+ // created method is removed
+}
+```
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index de25d79..29ba857 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -148,10 +148,13 @@
## Running Tests
For daily development you typically only want to run and debug individual tests.
-Run the local [Go proxy server](#go-server) and navigate for example to
-<http://localhost:8081/elements/shared/gr-account-entry/gr-account-entry_test.html>.
-Check "Disable cache" in the "Network" tab of Chrome's dev tools, so code
-changes are picked up on "reload".
+There are 2 types of fronted tests in gerrit:
+- Karma tests - all tests matches `*_test.js` pattern
+- web-component-tester(WCT) tests - all tests matches the `*_test.html` pattern.
+
+**Note:** WCT tests are deprecated. We are migrating to Karma tests now. If you are going to change
+something in a WCT test file, we strongly recommend to convert it to Karma tests before making
+any change. See [Converting WCT tests to Karma](#wct-to-karma).
Our CI integration ensures that all tests are run when you upload a change to
Gerrit, but you can also run all tests locally in headless mode:
@@ -160,6 +163,44 @@
npm test
```
+### Running Karma tests
+There are several ways to run Karma tests:
+
+* Run all Karma tests in headless mode:
+```sh
+npm run test:karma
+```
+
+* Run all Karma tests in debug mode (the command opens Chrome browser with
+the default Karma page; you should click the "Debug" button to start testing):
+```sh
+npm run test:karma:debug
+```
+
+* Run a single test file:
+```
+# Headless mode
+npm run test:karma async-foreach-behavior_test.js
+# Debug mode
+npm run test:karma:debug async-foreach-behavior_test.js
+```
+
+* You can run tests in IDE:
+ - [IntelliJ: running unit tests on Karma](https://www.jetbrains.com/help/idea/running-unit-tests-on-karma.html#ws_karma_running)
+
+### Running WCT tests
+
+Run the local [Go proxy server](#go-server) and navigate for example to
+<http://localhost:8081/elements/shared/gr-account-entry/gr-account-entry_test.html>.
+Check "Disable cache" in the "Network" tab of Chrome's dev tools, so code
+changes are picked up on "reload".
+
+You can also run all WCT tests locally in headless mode:
+
+```sh
+npm test:wct
+```
+
To allow the tests to run in Safari:
* In the Advanced preferences tab, check "Show Develop menu in menu bar".
@@ -171,6 +212,96 @@
WCT_HEADLESS_MODE=1 WCT_ARGS='--verbose -l chrome' ./polygerrit-ui/app/run_test.sh
```
+### <a name="wct-to-karma"></a>Converting WCT tests to Karma
+
+If you are want to change a WCT test file (any `..._test.html` file), please convert the file to a
+Karma test file before making any changes. It is better to make a conversion in a separate change,
+so any conversion-related problems can be catch at this step.
+
+Usually, our WCT tests files have the following structure:
+```Html
+<!-- Test header: meta, title, wct scripts -->
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<meta charset="utf-8">
+<title>gr-account-link</title>
+
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+
+<!-- Templates for test fixtures (optional) -->
+<test-fixture id="basic">
+ <template>
+ <gr-account-link></gr-account-link>
+ </template>
+ </test-fixture>
+
+<test-fixture id="other">
+ <template>
+ <gr-dialog>
+ <span>Hello!</span>
+ </gr-dialog>
+ </template>
+ </test-fixture>
+
+<!-- Tests -->
+<script type="module">
+// One or more imports:
+import '../../../test/common-test-setup.js';
+import ...;
+
+// Tests - one or more suites
+suite(..., () => {
+ ...
+ // instantiate 'basic' template:
+ element = fixture('basic');
+
+ ...
+ // instantiate 'other' template:
+ otherElements = fixture('other');
+
+);
+</script>
+```
+
+A conversion requires the following changes:
+* Rename the `..._test.html` file to the `..._test.js` file.
+* Remove test header (see a WCT test example above)
+* Remove all `<script...>` and `</script>` tags, but preserve javascript code
+* Change imports - use `test/common-test-setup-karma.js` instead of `test/common-test-setup.js`.
+Ensure, that the `common-test-setup-karma.js` import is placed above any other imports.
+* If there are test fixtures in the html file, move them inside a `<script>` tag and use
+the `fixtureFromTemplate` or `fixtureFromElement` (if there is only one element in a template)
+to define a test fixture template.
+* Use `instantiate` method instead of `fixture` method.
+
+After conversion, the Karma test file for the example above can look like:
+```Javascript
+import '../../../test/common-test-setup-karma.js';
+// Other imports:
+import ...
+
+// Define test fixtures templates:
+const fixture =
+ fixtureFromElement('gr-account-link');
+const otherFixture = fixtureFromTemplate(html`<gr-dialog>
+ <span>Hello!</span>
+</gr-dialog>
+`);
+
+// Tests - one or more suites
+suite(..., () => {
+ ...
+ // instantiate 'basic' template:
+ element = fixture.instantiate();
+
+ ...
+ // instantiate 'other' template:
+ otherElements = otherFixture.instantiate();
+
+);
+```
+
## Style guide
We follow the [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
@@ -299,4 +430,4 @@
// install all dependencies and start the server
npm start
-```
\ No newline at end of file
+```
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index 0302a76..e7506e0 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -109,7 +109,7 @@
"prefer-promise-reject-errors": "error",
"prefer-spread": "error",
"quote-props": ["error", "consistent-as-needed"],
- "semi": [2, "always"],
+ "semi": ["error", "always"],
"template-curly-spacing": "error",
"require-jsdoc": 0,
@@ -165,11 +165,9 @@
// You must not add anything new in this list!
// Instead export variables from modules
// TODO(dmfilippov): Remove global variables from polygerrit
- "GrReporting": "readonly",
// Global variables from 3rd party libraries.
// You should not add anything in this list, always try to import
// If import is not possible - you can extend this list
- "Polymer": "readonly",
"ShadyCSS": "readonly",
"linkify": "readonly",
"security": "readonly",
@@ -182,7 +180,13 @@
},
},
{
- "files": ["*.html", "common-test-setup.js"],
+ "files": [
+ "*.html",
+ "common-test-setup.js",
+ "common-test-setup-karma.js",
+ "*_test.js",
+ "a11y-test-utils.js",
+ ],
// Additional global variables allowed in tests
"globals": {
// Global variables from 3rd party test libraries/frameworks.
@@ -190,6 +194,7 @@
// variables from these libraries and import is not possible
"MockInteractions": "readonly",
"_": "readonly",
+ "axs": "readonly",
"a11ySuite": "readonly",
"assert": "readonly",
"expect": "readonly",
@@ -203,6 +208,8 @@
"suiteSetup": "readonly",
"teardown": "readonly",
"test": "readonly",
+ "fixtureFromElement": "readonly",
+ "fixtureFromTemplate": "readonly",
}
},
{
@@ -216,6 +223,7 @@
"globals": {
// Settings for samples. You can add globals here if you want to use it
"Gerrit": "readonly",
+ "Polymer": "readonly",
}
},
{
diff --git a/polygerrit-ui/app/BUILD b/polygerrit-ui/app/BUILD
index ca021db..096c665 100644
--- a/polygerrit-ui/app/BUILD
+++ b/polygerrit-ui/app/BUILD
@@ -58,6 +58,7 @@
name = "test-srcs-fg",
srcs = [
"test/common-test-setup.js",
+ "test/common-test-setup-karma.js",
"test/index.html",
":pg_code",
"@ui_dev_npm//:node_modules",
diff --git a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
deleted file mode 100644
index 1d50cc4..0000000
--- a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
+++ /dev/null
@@ -1,56 +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">
-<meta charset="utf-8">
-<title>async-foreach-behavior</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-<script type="module">
-import '../../test/common-test-setup.js';
-import {AsyncForeachBehavior} from './async-foreach-behavior.js';
-suite('async-foreach-behavior tests', () => {
- test('loops over each item', () => {
- const fn = sinon.stub().returns(Promise.resolve());
- return AsyncForeachBehavior.asyncForeach([1, 2, 3], fn)
- .then(() => {
- assert.isTrue(fn.calledThrice);
- assert.equal(fn.getCall(0).args[0], 1);
- assert.equal(fn.getCall(1).args[0], 2);
- assert.equal(fn.getCall(2).args[0], 3);
- });
- });
-
- test('halts on stop condition', () => {
- const stub = sinon.stub();
- const fn = (e, stop) => {
- stub(e);
- stop();
- return Promise.resolve();
- };
- return AsyncForeachBehavior.asyncForeach([1, 2, 3], fn)
- .then(() => {
- assert.isTrue(stub.calledOnce);
- assert.equal(stub.lastCall.args[0], 1);
- });
- });
-});
-</script>
diff --git a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.js b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.js
new file mode 100644
index 0000000..0a44884
--- /dev/null
+++ b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.js
@@ -0,0 +1,45 @@
+/**
+ * @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.
+ */
+
+import '../../test/common-test-setup-karma.js';
+import {AsyncForeachBehavior} from './async-foreach-behavior.js';
+suite('async-foreach-behavior tests', () => {
+ test('loops over each item', () => {
+ const fn = sinon.stub().returns(Promise.resolve());
+ return AsyncForeachBehavior.asyncForeach([1, 2, 3], fn)
+ .then(() => {
+ assert.isTrue(fn.calledThrice);
+ assert.equal(fn.getCall(0).args[0], 1);
+ assert.equal(fn.getCall(1).args[0], 2);
+ assert.equal(fn.getCall(2).args[0], 3);
+ });
+ });
+
+ test('halts on stop condition', () => {
+ const stub = sinon.stub();
+ const fn = (e, stop) => {
+ stub(e);
+ stop();
+ return Promise.resolve();
+ };
+ return AsyncForeachBehavior.asyncForeach([1, 2, 3], fn)
+ .then(() => {
+ assert.isTrue(stub.calledOnce);
+ assert.equal(stub.lastCall.args[0], 1);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior.js b/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior.js
index 3c48fbe..51c52f1 100644
--- a/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior.js
+++ b/polygerrit-ui/app/behaviors/gr-admin-nav-behavior/gr-admin-nav-behavior.js
@@ -87,7 +87,7 @@
let links = ADMIN_LINKS.slice(0);
let expandedSection;
- const isExernalLink = link => link.url[0] !== '/';
+ const isExternalLink = link => link.url[0] !== '/';
// Append top-level links that are defined by plugins.
links.push(...getAdminMenuLinks().map(link => {
@@ -95,10 +95,10 @@
url: link.url,
name: link.text,
capability: link.capability || null,
- noBaseUrl: !isExernalLink(link),
+ noBaseUrl: !isExternalLink(link),
view: null,
viewableToAll: !link.capability,
- target: isExernalLink(link) ? '_blank' : null,
+ target: isExternalLink(link) ? '_blank' : null,
};
}));
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.js b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.js
index 7745b42..be8c811 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.js
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.js
@@ -15,12 +15,11 @@
* limitations under the License.
*/
+import {SpecialFilePath} from '../../constants/constants.js';
+
/** @polymerBehavior Gerrit.PathListBehavior */
export const PathListBehavior = {
- COMMIT_MESSAGE_PATH: '/COMMIT_MSG',
- MERGE_LIST_PATH: '/MERGE_LIST',
-
/**
* @param {string} a
* @param {string} b
@@ -28,18 +27,18 @@
*/
specialFilePathCompare(a, b) {
// The commit message always goes first.
- if (a === PathListBehavior.COMMIT_MESSAGE_PATH) {
+ if (a === SpecialFilePath.COMMIT_MESSAGE) {
return -1;
}
- if (b === PathListBehavior.COMMIT_MESSAGE_PATH) {
+ if (b === SpecialFilePath.COMMIT_MESSAGE) {
return 1;
}
// The merge list always comes next.
- if (a === PathListBehavior.MERGE_LIST_PATH) {
+ if (a === SpecialFilePath.MERGE_LIST) {
return -1;
}
- if (b === PathListBehavior.MERGE_LIST_PATH) {
+ if (b === SpecialFilePath.MERGE_LIST) {
return 1;
}
@@ -67,10 +66,22 @@
return aFile.localeCompare(bFile) || a.localeCompare(b);
},
+ shouldHideFile(file) {
+ return file === SpecialFilePath.PATCHSET_LEVEL_COMMENTS;
+ },
+
+ addUnmodifiedFiles(files, commentedPaths) {
+ Object.keys(commentedPaths).forEach(commentedPath => {
+ if (files.hasOwnProperty(commentedPath) ||
+ this.shouldHideFile(commentedPath)) { return; }
+ files[commentedPath] = {status: 'U'};
+ });
+ },
+
computeDisplayPath(path) {
- if (path === PathListBehavior.COMMIT_MESSAGE_PATH) {
+ if (path === SpecialFilePath.COMMIT_MESSAGE) {
return 'Commit message';
- } else if (path === PathListBehavior.MERGE_LIST_PATH) {
+ } else if (path === SpecialFilePath.MERGE_LIST) {
return 'Merge list';
}
return path;
@@ -78,8 +89,8 @@
isMagicPath(path) {
return !!path &&
- (path === PathListBehavior.COMMIT_MESSAGE_PATH || path ===
- PathListBehavior.MERGE_LIST_PATH);
+ (path === SpecialFilePath.COMMIT_MESSAGE || path ===
+ SpecialFilePath.MERGE_LIST);
},
computeTruncatedPath(path) {
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
index 1b7a42a..cf5105e 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
@@ -24,6 +24,8 @@
<script type="module">
import '../../test/common-test-setup.js';
import {PathListBehavior} from './gr-path-list-behavior.js';
+import {SpecialFilePath} from '../../constants/constants.js';
+
suite('gr-path-list-behavior tests', () => {
test('special sort', () => {
const sort = PathListBehavior.specialFilePathCompare;
@@ -63,6 +65,20 @@
assert.isTrue(isMagic('/MERGE_LIST'));
});
+ test('patchset level comments are hidden', () => {
+ const commentedPaths = {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: true,
+ 'file1.txt': true,
+ };
+
+ const files = {'file2.txt': {status: 'M'}};
+ PathListBehavior.addUnmodifiedFiles(files, commentedPaths);
+ assert.equal(files['file1.txt'].status, 'U');
+ assert.equal(files['file2.txt'].status, 'M');
+ assert.isFalse(files.hasOwnProperty(
+ SpecialFilePath.PATCHSET_LEVEL_COMMENTS));
+ });
+
test('truncatePath with long path should add ellipsis', () => {
const truncatePath = PathListBehavior.truncatePath;
let path = 'level1/level2/level3/level4/file.js';
diff --git a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
index 2a592f0..cc8b55a 100644
--- a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
+++ b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../scripts/bundled-polymer.js';
-
import '../../elements/shared/gr-tooltip/gr-tooltip.js';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {getRootElement} from '../../scripts/rootElement.js';
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js
index cb21a9f..09e3b72 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js
@@ -95,12 +95,6 @@
NOTE: doc-only shortcuts will not be customizable in the same way that other
shortcuts are.
*/
-/*
- FIXME(polymer-modulizer): the above comments were extracted
- from HTML and may be out of place here. Review them and
- then delete this comment!
-*/
-import '../../scripts/bundled-polymer.js';
import {IronA11yKeysBehavior} from '@polymer/iron-a11y-keys-behavior/iron-a11y-keys-behavior.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.js b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.js
index 919a763..05bf169 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.js
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.js
@@ -14,8 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../scripts/bundled-polymer.js';
import {BaseUrlBehavior} from '../base-url-behavior/base-url-behavior.js';
+import {ChangeStatus} from '../../constants/constants.js';
/** @polymerBehavior Gerrit.RESTClientBehavior */
export const RESTClientBehavior = [{
@@ -28,12 +28,6 @@
REWRITE: 'REWRITE',
},
- ChangeStatus: {
- ABANDONED: 'ABANDONED',
- MERGED: 'MERGED',
- NEW: 'NEW',
- },
-
// Must be kept in sync with the ListChangesOption enum and protobuf.
ListChangesOption: {
LABELS: 0,
@@ -125,7 +119,7 @@
},
changeIsOpen(change) {
- return change && change.status === this.ChangeStatus.NEW;
+ return change && change.status === ChangeStatus.NEW;
},
/**
@@ -136,9 +130,9 @@
*/
changeStatuses(change, opt_options) {
const states = [];
- if (change.status === this.ChangeStatus.MERGED) {
+ if (change.status === ChangeStatus.MERGED) {
states.push('Merged');
- } else if (change.status === this.ChangeStatus.ABANDONED) {
+ } else if (change.status === ChangeStatus.ABANDONED) {
states.push('Abandoned');
} else if (change.mergeable === false ||
(opt_options && opt_options.mergeable === false)) {
diff --git a/polygerrit-ui/app/constants/constants.js b/polygerrit-ui/app/constants/constants.js
index cab50f6..5072594 100644
--- a/polygerrit-ui/app/constants/constants.js
+++ b/polygerrit-ui/app/constants/constants.js
@@ -19,8 +19,9 @@
* @enum
* @desc Tab names for primary tabs on change view page.
*/
-export const PrimaryTabs = {
+export const PrimaryTab = {
FILES: '_files',
+ COMMENT_THREADS: '_commentThreads',
FINDINGS: '_findings',
};
@@ -28,8 +29,55 @@
* @enum
* @desc Tab names for secondary tabs on change view page.
*/
-export const SecondaryTabs = {
+export const SecondaryTab = {
CHANGE_LOG: '_changeLog',
- COMMENT_THREADS: '_commentThreads',
};
+/**
+ * @enum
+ * @desc Tag names of change log messages.
+ */
+export const MessageTag = {
+ TAG_DELETE_REVIEWER: 'autogenerated:gerrit:deleteReviewer',
+ TAG_NEW_PATCHSET: 'autogenerated:gerrit:newPatchSet',
+ TAG_NEW_WIP_PATCHSET: 'autogenerated:gerrit:newWipPatchSet',
+ TAG_REVIEWER_UPDATE: 'autogenerated:gerrit:reviewerUpdate',
+ TAG_SET_PRIVATE: 'autogenerated:gerrit:setPrivate',
+ TAG_UNSET_PRIVATE: 'autogenerated:gerrit:unsetPrivate',
+ TAG_SET_READY: 'autogenerated:gerrit:setReadyForReview',
+ TAG_SET_WIP: 'autogenerated:gerrit:setWorkInProgress',
+ TAG_SET_ASSIGNEE: 'autogenerated:gerrit:setAssignee',
+ TAG_UNSET_ASSIGNEE: 'autogenerated:gerrit:deleteAssignee',
+};
+
+/**
+ * @enum
+ * @desc Modes for gr-diff-cursor
+ * The scroll behavior for the cursor. Values are 'never' and
+ * 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
+ * the viewport.
+ */
+export const ScrollMode = {
+ KEEP_VISIBLE: 'keep-visible',
+ NEVER: 'never',
+};
+
+/**
+ * @enum
+ * @desc Specifies status for a change
+ */
+export const ChangeStatus = {
+ ABANDONED: 'ABANDONED',
+ MERGED: 'MERGED',
+ NEW: 'NEW',
+};
+
+/**
+ * @enum
+ * @desc Special file paths
+ */
+export const SpecialFilePath = {
+ PATCHSET_LEVEL_COMMENTS: '/PATCHSET_LEVEL',
+ COMMIT_MESSAGE: '/COMMIT_MSG',
+ MERGE_LIST: '/MERGE_LIST',
+};
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
index e07a64e..632387e 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -51,7 +50,7 @@
const LABEL = 'Label';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccessSection extends mixinBehaviors( [
AccessBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.js
similarity index 92%
rename from polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
rename to polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.js
index 95345fe..2128e29 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.js
@@ -1,47 +1,32 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2017 The Android Open Source Project
+/**
+ * @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.
+ */
-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">
-<meta charset="utf-8">
-<title>gr-access-section</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/page/page.js"></script>
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-
-<test-fixture id="basic">
- <template>
- <gr-access-section></gr-access-section>
- </template>
-</test-fixture>
-
-<script type="module">
-import '../../../test/common-test-setup.js';
+import '../../../test/common-test-setup-karma.js';
import './gr-access-section.js';
+
+const fixture = fixtureFromElement('gr-access-section');
+
suite('gr-access-section tests', () => {
let element;
let sandbox;
setup(() => {
sandbox = sinon.sandbox.create();
- element = fixture('basic');
+ element = fixture.instantiate();
});
teardown(() => {
@@ -245,7 +230,7 @@
test('_computeSectionName', () => {
let name;
// When computing the section name for an undefined name, it means a
- // new section is being added. In this case, it should defualt to
+ // new section is being added. In this case, it should default to
// 'refs/heads/*'.
element._editingRef = false;
assert.equal(element._computeSectionName(name),
@@ -477,7 +462,7 @@
});
test('_handleValueChange', () => {
- // For an exising section.
+ // For an existing section.
const modifiedHandler = sandbox.stub();
element.section = {id: 'refs/for/bar', value: {permissions: {}}};
assert.notOk(element.section.value.updatedId);
@@ -553,4 +538,3 @@
});
});
});
-</script>
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
index 36e2cc4..865fd33 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
@@ -33,7 +32,7 @@
/**
* @appliesMixin ListViewMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAdminGroupList extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
index b318ee6..25ba83e 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-menu-page-styles.js';
import '../../../styles/gr-page-nav-styles.js';
import '../../../styles/shared-styles.js';
@@ -48,7 +47,7 @@
const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAdminView extends mixinBehaviors( [
AdminNavBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
index b6b21bd..288af4c 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -30,7 +28,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmDeleteItemDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
index 3347655..e16f5ce 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
import '@polymer/iron-input/iron-input.js';
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
@@ -37,7 +34,7 @@
const REF_PREFIX = 'refs/heads/';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCreateChangeDialog extends mixinBehaviors( [
BaseUrlBehavior,
@@ -152,11 +149,7 @@
} else if (config && config.configured_value === 'FALSE') {
return false;
} else if (config && config.configured_value === 'INHERIT') {
- if (config && config.inherited_value) {
- return true;
- } else {
- return false;
- }
+ return !!(config && config.inherited_value);
} else {
return false;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
index 87105a7..eaee4a4 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
@@ -57,7 +57,7 @@
},
});
element = fixture('basic');
- element.repoName = 'test-repo',
+ element.repoName = 'test-repo';
element._repoConfig = {
private_by_default: {
configured_value: 'FALSE',
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
index b21bdde..7f33663 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -30,7 +28,7 @@
import page from 'page/page.mjs';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCreateGroupDialog extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
index 72a6b99..eb131f5 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -37,7 +35,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCreatePointerDialog extends mixinBehaviors( [
BaseUrlBehavior,
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 040f41b..0410f14 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
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -33,7 +31,7 @@
import page from 'page/page.mjs';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCreateRepoDialog extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
index a3c05cb..2c0c1302 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-date-formatter/gr-date-formatter.js';
@@ -32,7 +31,7 @@
const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrGroupAuditLog extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
index 45f7612..c54a709 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/gr-subpage-styles.js';
@@ -41,7 +40,7 @@
const URL_REGEX = '^(?:[a-z]+:)?//';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrGroupMembers extends mixinBehaviors( [
BaseUrlBehavior,
@@ -122,12 +121,12 @@
this._groupName = config.name;
promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
- this._isAdmin = isAdmin ? true : false;
+ this._isAdmin = !!isAdmin;
}));
promises.push(this.$.restAPI.getIsGroupOwner(config.name)
.then(isOwner => {
- this._groupOwner = isOwner ? true : false;
+ this._groupOwner = !!isOwner;
}));
promises.push(this.$.restAPI.getGroupMembers(config.name).then(
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
index 4dd9a7b..3a5bfd8 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
@@ -302,32 +302,32 @@
});
test('delete member', () => {
- const deletelBtns = dom(element.root)
+ const deleteBtns = dom(element.root)
.querySelectorAll('.deleteMembersButton');
- MockInteractions.tap(deletelBtns[0]);
+ MockInteractions.tap(deleteBtns[0]);
assert.equal(element._itemId, '1000097');
assert.equal(element._itemName, 'jane');
- MockInteractions.tap(deletelBtns[1]);
+ MockInteractions.tap(deleteBtns[1]);
assert.equal(element._itemId, '1000096');
assert.equal(element._itemName, 'Test User');
- MockInteractions.tap(deletelBtns[2]);
+ MockInteractions.tap(deleteBtns[2]);
assert.equal(element._itemId, '1000095');
assert.equal(element._itemName, 'Gerrit');
- MockInteractions.tap(deletelBtns[3]);
+ MockInteractions.tap(deleteBtns[3]);
assert.equal(element._itemId, '1000098');
assert.equal(element._itemName, '1000098');
});
test('delete included groups', () => {
- const deletelBtns = dom(element.root)
+ const deleteBtns = dom(element.root)
.querySelectorAll('.deleteIncludedGroupButton');
- MockInteractions.tap(deletelBtns[0]);
+ MockInteractions.tap(deleteBtns[0]);
assert.equal(element._itemId, 'testId');
assert.equal(element._itemName, 'testName');
- MockInteractions.tap(deletelBtns[1]);
+ MockInteractions.tap(deleteBtns[1]);
assert.equal(element._itemId, 'testId2');
assert.equal(element._itemName, 'testName2');
- MockInteractions.tap(deletelBtns[2]);
+ MockInteractions.tap(deleteBtns[2]);
assert.equal(element._itemId, 'testId3');
assert.equal(element._itemName, 'testName3');
});
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
index 1c7cc91..49cd8ea 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/gr-subpage-styles.js';
@@ -43,7 +42,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrGroup extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -142,12 +141,12 @@
this._groupIsInternal = !!config.id.match(INTERNAL_GROUP_REGEX);
promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
- this._isAdmin = isAdmin ? true : false;
+ this._isAdmin = !!isAdmin;
}));
promises.push(this.$.restAPI.getIsGroupOwner(config.name)
.then(isOwner => {
- this._groupOwner = isOwner ? true : false;
+ this._groupOwner = !!isOwner;
}));
// If visible to all is undefined, set to false. If it is defined
@@ -262,7 +261,7 @@
}
_computeGroupDisabled(owner, admin, groupIsInternal) {
- return groupIsInternal && (admin || owner) ? false : true;
+ return !(groupIsInternal && (admin || owner));
}
_getGroupUUID(id) {
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.js
index e11f989..0af87ad 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.js
@@ -126,7 +126,7 @@
<h3 id="options" class$="[[_computeHeaderClass(_options)]]">
Group Options
</h3>
- <fieldset id="visableToAll">
+ <fieldset>
<section>
<span class="title">
Make group visible to all registered users
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
index 9fac11e..d25ee76 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import '../../../styles/gr-form-styles.js';
@@ -48,7 +47,7 @@
* Fired when a permission that was previously added was removed.
*
* @event added-permission-removed
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrPermission extends mixinBehaviors( [
AccessBehavior,
@@ -211,11 +210,10 @@
// It is possible to have a label name that is not included in the
// 'labels' object. In this case, treat it like anything else.
if (!labels[labelName]) { return; }
- const label = {
+ return {
name: labelName,
values: this._computeLabelValues(labels[labelName].values),
};
- return label;
}
_computeLabelValues(values) {
@@ -299,7 +297,7 @@
}
// Wait for new rule to get value populated via gr-rule-editor, and then
- // add to permission values as well, so that the change gets propogated
+ // add to permission values as well, so that the change gets propagated
// back to the section. Since the rule is inside a dom-repeat, a flush
// is needed.
flush();
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.js b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.js
index 318c2c3..d9d37f6 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.js
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import '../../../styles/gr-form-styles.js';
@@ -27,7 +25,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-plugin-config-array-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrPluginConfigArrayEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
index 154af6e..868a7cd 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-list-view/gr-list-view.js';
@@ -29,7 +27,7 @@
/**
* @appliesMixin ListViewMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrPluginList extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
index 9aa81f8..f6a1c10 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-menu-page-styles.js';
import '../../../styles/gr-subpage-styles.js';
import '../../../styles/shared-styles.js';
@@ -83,7 +81,7 @@
Defs.projectAccessInput;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoAccess extends mixinBehaviors( [
AccessBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
index 53b4989..d161423 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-repo-command_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrRepoCommand extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
index 1f1dc5b..03a2bd3 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/gr-subpage-styles.js';
@@ -43,7 +41,7 @@
const CREATE_CHANGE_SUCCEEDED_MESSAGE = 'Navigating to change';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoCommands extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
index 072fc721..f47ff76 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -26,7 +25,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoDashboards extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
index e8b3d9a..e3a9958 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
@@ -16,7 +16,6 @@
*/
import '@polymer/iron-input/iron-input.js';
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
@@ -47,7 +46,7 @@
/**
* @appliesMixin ListViewMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoDetailList extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
index 59abb72..a8119e6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-dialog/gr-dialog.js';
@@ -33,7 +31,7 @@
/**
* @appliesMixin ListViewMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoList extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.js b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.js
index d01f9ab..a70aa11 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import '../../../styles/gr-form-styles.js';
@@ -34,7 +32,7 @@
import {RepoPluginConfig} from '../../../behaviors/gr-repo-plugin-config-behavior/gr-repo-plugin-config-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoPluginConfig extends mixinBehaviors( [
RepoPluginConfig,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
index 05ae73d..f272708 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '@polymer/iron-input/iron-input.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
@@ -68,7 +66,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepo extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -355,8 +353,8 @@
commands.push({
title,
command: commandObj[title]
- .replace(/\$\{project\}/gi, encodeURI(repo))
- .replace(/\$\{project-base-name\}/gi,
+ .replace(/\${project}/gi, encodeURI(repo))
+ .replace(/\${project-base-name}/gi,
encodeURI(repo.substring(repo.lastIndexOf('/') + 1))),
});
}
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
index 234015a..99957ff 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -79,7 +77,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRuleEditor extends mixinBehaviors( [
AccessBehavior,
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index da13492..a3fe990 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-change-list-styles.js';
import '../../shared/gr-account-link/gr-account-link.js';
import '../../shared/gr-change-star/gr-change-star.js';
@@ -50,7 +49,7 @@
/**
* @appliesMixin RESTClientMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeListItem extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
index c416b11..361ad83 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-icons/gr-icons.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-change-list/gr-change-list.js';
@@ -45,7 +44,7 @@
const LIMIT_OPERATOR_PATTERN = /\blimit:(\d+)/i;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeListView extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index 0a19ae1..bd78ae9 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-change-list-styles.js';
import '../../shared/gr-cursor-manager/gr-cursor-manager.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -45,7 +44,7 @@
const MAX_SHORTCUT_CHARS = 5;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeList extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
index 17150df..e5193f8 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
@@ -138,7 +138,7 @@
<gr-cursor-manager
id="cursor"
index="{{selectedIndex}}"
- scroll-behavior="keep-visible"
+ scroll-mode="keep-visible"
focus-on-move=""
></gr-cursor-manager>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.js b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.js
index 3758a78..d9fd378 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.js
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -24,7 +23,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-create-change-help_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCreateChangeHelp extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.js b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.js
index 7e5e749..cc53e49 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.js
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-overlay/gr-overlay.js';
@@ -30,7 +29,7 @@
PUSH_PREFIX: 'git push origin HEAD:refs/for/',
};
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCreateCommandsDialog extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.js b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.js
index f8757ba..9062a3f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.js
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-overlay/gr-overlay.js';
@@ -29,7 +28,7 @@
* name and the branch name.
*
* @event confirm
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCreateDestinationDialog extends GestureEventListeners(
LegacyElementMixin(
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
index 8b8b981..1cc2316 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../gr-change-list/gr-change-list.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-overlay/gr-overlay.js';
@@ -34,11 +31,12 @@
import {htmlTemplate} from './gr-dashboard-view_html.js';
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {appContext} from '../../../services/app-context.js';
const PROJECT_PLACEHOLDER_PATTERN = /\$\{project\}/g;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDashboardView extends mixinBehaviors( [
RESTClientBehavior,
@@ -98,6 +96,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
static get observers() {
return [
'_paramsChanged(params.*)',
@@ -197,7 +200,7 @@
})
.then(() => {
this._maybeShowDraftsBanner();
- this.$.reporting.dashboardDisplayed();
+ this.reporting.dashboardDisplayed();
})
.catch(err => {
this.dispatchEvent(new CustomEvent('title-change', {
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.js
index 3389bd0..cf1036f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.js
@@ -119,5 +119,4 @@
></gr-create-destination-dialog>
<gr-create-commands-dialog id="commandsDialog"></gr-create-commands-dialog>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
index 5965d06..2fcf233 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
@@ -357,7 +357,7 @@
});
element.addEventListener('page-error', e => {
assert.strictEqual(e.detail.response, response);
- done();
+ paramsChangedPromise.then(done);
});
element.params = {
view: GerritNav.View.DASHBOARD,
@@ -367,14 +367,14 @@
});
test('params change triggers dashboardDisplayed()', () => {
- sandbox.stub(element.$.reporting, 'dashboardDisplayed');
+ sandbox.stub(element.reporting, 'dashboardDisplayed');
element.params = {
view: GerritNav.View.DASHBOARD,
project: 'project',
dashboard: 'dashboard',
};
return paramsChangedPromise.then(() => {
- assert.isTrue(element.$.reporting.dashboardDisplayed.calledOnce);
+ assert.isTrue(element.reporting.dashboardDisplayed.calledOnce);
});
});
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard.js b/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard.js
deleted file mode 100644
index 2523700..0000000
--- a/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import '../../../scripts/bundled-polymer.js';
-
-import '../gr-change-list/gr-change-list.js';
-import '../gr-create-change-help/gr-create-change-help.js';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {htmlTemplate} from './gr-embed-dashboard_html.js';
-
-/** @extends Polymer.Element */
-class GrEmbedDashboard extends GestureEventListeners(
- LegacyElementMixin(
- PolymerElement)) {
- static get template() { return htmlTemplate; }
-
- static get is() { return 'gr-embed-dashboard'; }
-
- static get properties() {
- return {
- account: Object,
- sections: Array,
- preferences: Object,
- showNewUserHelp: Boolean,
- };
- }
-}
-
-customElements.define(GrEmbedDashboard.is, GrEmbedDashboard);
diff --git a/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard_html.js b/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard_html.js
deleted file mode 100644
index 802e365..0000000
--- a/polygerrit-ui/app/elements/change-list/gr-embed-dashboard/gr-embed-dashboard_html.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-export const htmlTemplate = html`
- <gr-change-list
- show-star=""
- account="[[account]]"
- preferences="[[preferences]]"
- sections="[[sections]]"
- >
- <div id="emptyOutgoing" slot="empty-outgoing">
- <template is="dom-if" if="[[showNewUserHelp]]">
- <gr-create-change-help></gr-create-change-help>
- </template>
- <template is="dom-if" if="[[!showNewUserHelp]]">
- No changes
- </template>
- </div>
- </gr-change-list>
-`;
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.js b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.js
index 5f0021e..303c612 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.js
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/dashboard-header-styles.js';
import '../../../styles/shared-styles.js';
@@ -26,7 +25,7 @@
import {htmlTemplate} from './gr-repo-header_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrRepoHeader extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
index 6bb1bf8..7901c53 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
@@ -30,7 +29,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrUserHeader extends GestureEventListeners(
LegacyElementMixin(
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index d65757a..03a64a5 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../admin/gr-create-change-dialog/gr-create-change-dialog.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-dropdown/gr-dropdown.js';
@@ -44,6 +41,7 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
+import {appContext} from '../../../services/app-context.js';
const ERR_BRANCH_EMPTY = 'The destination branch can’t be empty.';
const ERR_COMMIT_EMPTY = 'The commit message can’t be empty.';
@@ -232,7 +230,7 @@
const SKIP_ACTION_KEYS = [ChangeActions.REVERT_SUBMISSION];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeActions extends mixinBehaviors( [
PatchSetBehavior,
@@ -272,6 +270,7 @@
this.ActionType = ActionType;
this.ChangeActions = ChangeActions;
this.RevisionActions = RevisionActions;
+ this.reporting = appContext.reportingService;
}
static get properties() {
@@ -998,7 +997,7 @@
this._handleAction(type, key);
}
- _handleOveflowItemTap(e) {
+ _handleOverflowItemTap(e) {
e.preventDefault();
const el = dom(e).localTarget;
const key = e.detail.action.__key;
@@ -1014,7 +1013,7 @@
}
_handleAction(type, key) {
- this.$.reporting.reportInteraction(`${type}-${key}`);
+ this.reporting.reportInteraction(`${type}-${key}`);
switch (type) {
case ActionType.REVISION:
this._handleRevisionAction(key);
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.js
index f12e600..916a56f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.js
@@ -140,7 +140,7 @@
tabindex="0"
vertical-offset="32"
horizontal-align="right"
- on-tap-item="_handleOveflowItemTap"
+ on-tap-item="_handleOverflowItemTap"
hidden$="[[_shouldHideActions(_menuActions.*, _loading)]]"
disabled-ids="[[_disabledMenuActions]]"
items="[[_menuActions]]"
@@ -271,5 +271,4 @@
</gr-overlay>
<gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting" category="change-actions"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index acf17ea..a763250 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -1966,7 +1966,7 @@
test('_handleAction reports', () => {
sandbox.stub(element, '_fireAction');
- const reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
+ const reportStub = sandbox.stub(element.reporting, 'reportInteraction');
element._handleAction('type', 'key');
assert.isTrue(reportStub.called);
assert.equal(reportStub.lastCall.args[0], 'type-key');
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index fda13cd..9d3b455 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../../styles/gr-change-metadata-shared-styles.js';
import '../../../styles/gr-change-view-integration-shared-styles.js';
@@ -45,6 +43,7 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../../../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {ChangeStatus} from '../../../constants/constants.js';
const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
@@ -78,7 +77,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeMetadata extends mixinBehaviors( [
RESTClientBehavior,
@@ -323,7 +322,7 @@
}
_computeShowRequirements(change) {
- if (change.status !== this.ChangeStatus.NEW) {
+ if (change.status !== ChangeStatus.NEW) {
// TODO(maximeg) change this to display the stored
// requirements, once it is implemented server-side.
return false;
@@ -399,7 +398,7 @@
_computeBranchUrl(project, branch) {
if (!this.change || !this.change.status) return '';
return GerritNav.getUrlForBranch(branch, project,
- this.change.status == this.ChangeStatus.NEW ? 'open' :
+ this.change.status == ChangeStatus.NEW ? 'open' :
this.change.status.toLowerCase());
}
@@ -462,7 +461,7 @@
*
* @param {!Object} change
* @param {string} role One of the values from _CHANGE_ROLE
- * @return {Object|null} either an accound or null.
+ * @return {Object|null} either an account or null.
*/
_getNonOwnerRole(change, role) {
if (!change || !change.current_revision ||
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
index d301813..78627a7 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-icons/gr-icons.js';
@@ -30,7 +28,7 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeRequirements extends mixinBehaviors( [
RESTClientBehavior,
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 968f56f..5035818 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
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-tabs/paper-tabs.js';
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
import '../../plugins/gr-endpoint-param/gr-endpoint-param.js';
@@ -66,9 +63,11 @@
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
import {RevisionInfo} from '../../shared/revision-info/revision-info.js';
-import {PrimaryTabs, SecondaryTabs} from '../../../constants/constants.js';
+import {PrimaryTab, SecondaryTab} from '../../../constants/constants.js';
import {NO_ROBOT_COMMENTS_THREADS_MSG} from '../../../constants/messages.js';
import {appContext} from '../../../services/app-context.js';
+import {ExperimentIds} from '../../../services/flags.js';
+import {ChangeStatus} from '../../../constants/constants.js';
const CHANGE_ID_ERROR = {
MISMATCH: 'mismatch',
@@ -131,7 +130,7 @@
/**
* @appliesMixin RESTClientMixin
* @appliesMixin PatchSetMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeView extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -272,8 +271,8 @@
_constants: {
type: Object,
value: {
- SecondaryTabs,
- PrimaryTabs,
+ SecondaryTab,
+ PrimaryTab,
},
},
_messages: {
@@ -407,7 +406,7 @@
*/
_activeTabs: {
type: Array,
- value: [PrimaryTabs.FILES, SecondaryTabs.CHANGE_LOG],
+ value: [PrimaryTab.FILES, SecondaryTab.CHANGE_LOG],
},
_showAllRobotComments: {
type: Boolean,
@@ -449,6 +448,7 @@
constructor() {
super();
this.flagsService = appContext.flagsService;
+ this.reporting = appContext.reportingService;
}
/** @override */
@@ -539,7 +539,7 @@
}
_isChangeLogExperimentEnabled() {
- return this.flagsService.isEnabled('UiFeature__cleaner_changelog');
+ return this.flagsService.isEnabled(ExperimentIds.CLEANER_CHANGELOG);
}
get messagesList() {
@@ -626,7 +626,7 @@
}
if (paperTabs.selected !== activeIndex) {
paperTabs.selected = activeIndex;
- this.$.reporting.reportInteraction('show-tab', {tabName});
+ this.reporting.reportInteraction('show-tab', {tabName});
}
return tabName;
}
@@ -741,7 +741,7 @@
_computeHideEditCommitMessage(
loggedIn, editing, change, editMode, collapsed, collapsible) {
if (!loggedIn || editing ||
- (change && change.status === this.ChangeStatus.MERGED) ||
+ (change && change.status === ChangeStatus.MERGED) ||
editMode ||
(collapsed && collapsible)) {
return true;
@@ -820,8 +820,7 @@
// Get any new drafts that have been saved in the diff view and show
// in the comment thread view.
this._reloadDrafts().then(() => {
- this._commentThreads = this._changeComments.getAllThreadsForChange()
- .map(c => Object.assign({}, c));
+ this._commentThreads = this._changeComments.getAllThreadsForChange();
flush();
});
}
@@ -995,7 +994,7 @@
_handleReplySent(e) {
this.addEventListener('change-details-loaded',
() => {
- this.$.reporting.timeEnd(SEND_REPLY_TIMING_LABEL);
+ this.reporting.timeEnd(SEND_REPLY_TIMING_LABEL);
}, {once: true});
this.$.replyOverlay.close();
this._reload();
@@ -1090,7 +1089,7 @@
}
_initActiveTabs(params = {}) {
- let primaryTab = PrimaryTabs.FILES;
+ let primaryTab = PrimaryTab.FILES;
if (params.queryMap && params.queryMap.has('tab')) {
primaryTab = params.queryMap.get('tab');
}
@@ -1102,7 +1101,7 @@
// TODO: should drop this once we move CommentThreads tab
// to primary as well
- let secondaryTab = SecondaryTabs.CHANGE_LOG;
+ let secondaryTab = SecondaryTab.CHANGE_LOG;
if (params.queryMap && params.queryMap.has('secondaryTab')) {
secondaryTab = params.queryMap.get('secondaryTab');
}
@@ -1199,7 +1198,7 @@
.then(this._getLoggedIn.bind(this))
.then(loggedIn => {
if (!loggedIn || !this._change ||
- this._change.status !== this.ChangeStatus.MERGED) {
+ this._change.status !== ChangeStatus.MERGED) {
// Do not display dialog if not logged-in or the change is not
// merged.
return;
@@ -1739,11 +1738,18 @@
_recomputeComments(comments) {
this._changeComments = comments;
- this._diffDrafts = Object.assign({}, this._changeComments.drafts);
- this._commentThreads = this._changeComments.getAllThreadsForChange()
- .map(c => Object.assign({}, c));
+ this._diffDrafts = {...this._changeComments.drafts};
+ this._commentThreads = this._changeComments.getAllThreadsForChange();
this._draftCommentThreads = this._commentThreads
- .filter(c => c.comments[c.comments.length - 1].__draft);
+ .filter(thread => thread.comments[thread.comments.length - 1].__draft)
+ .map(thread => {
+ const copiedThread = {...thread};
+ // Make a hardcopy of all comments and collapse all but last one
+ const commentsInThread = copiedThread.comments = thread.comments
+ .map(comment => { return {...comment, collapsed: true}; });
+ commentsInThread[commentsInThread.length - 1].collapsed = false;
+ return copiedThread;
+ });
}
/**
@@ -1758,8 +1764,8 @@
_reload(opt_isLocationChange) {
this._loading = true;
this._relatedChangesCollapsed = true;
- this.$.reporting.time(CHANGE_RELOAD_TIMING_LABEL);
- this.$.reporting.time(CHANGE_DATA_TIMING_LABEL);
+ this.reporting.time(CHANGE_RELOAD_TIMING_LABEL);
+ this.reporting.time(CHANGE_DATA_TIMING_LABEL);
// Array to house all promises related to data requests.
const allDataPromises = [];
@@ -1778,9 +1784,9 @@
{bubbles: true, composed: true}));
})
.then(() => {
- this.$.reporting.timeEnd(CHANGE_RELOAD_TIMING_LABEL);
+ this.reporting.timeEnd(CHANGE_RELOAD_TIMING_LABEL);
if (opt_isLocationChange) {
- this.$.reporting.changeDisplayed();
+ this.reporting.changeDisplayed();
}
});
@@ -1850,9 +1856,9 @@
}
Promise.all(allDataPromises).then(() => {
- this.$.reporting.timeEnd(CHANGE_DATA_TIMING_LABEL);
+ this.reporting.timeEnd(CHANGE_DATA_TIMING_LABEL);
if (opt_isLocationChange) {
- this.$.reporting.changeFullyLoaded();
+ this.reporting.changeFullyLoaded();
}
});
@@ -1878,8 +1884,8 @@
// If the change is closed, it is not mergeable. Note: already merged
// changes are obviously not mergeable, but the mergeability API will not
// answer for abandoned changes.
- if (this._change.status === this.ChangeStatus.MERGED ||
- this._change.status === this.ChangeStatus.ABANDONED) {
+ if (this._change.status === ChangeStatus.MERGED ||
+ this._change.status === ChangeStatus.ABANDONED) {
this._mergeable = false;
return Promise.resolve();
}
@@ -2059,11 +2065,11 @@
let toastMessage = null;
if (!result.isLatest) {
toastMessage = ReloadToastMessage.NEWER_REVISION;
- } else if (result.newStatus === this.ChangeStatus.MERGED) {
+ } else if (result.newStatus === ChangeStatus.MERGED) {
toastMessage = ReloadToastMessage.MERGED;
- } else if (result.newStatus === this.ChangeStatus.ABANDONED) {
+ } else if (result.newStatus === ChangeStatus.ABANDONED) {
toastMessage = ReloadToastMessage.ABANDONED;
- } else if (result.newStatus === this.ChangeStatus.NEW) {
+ } else if (result.newStatus === ChangeStatus.NEW) {
toastMessage = ReloadToastMessage.RESTORED;
} else if (result.newMessages) {
toastMessage = ReloadToastMessage.NEW_MESSAGE;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.js
index e8f8a68..7548017 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.js
@@ -551,7 +551,18 @@
</section>
<paper-tabs id="primaryTabs" on-selected-changed="_setActivePrimaryTab">
- <paper-tab data-name$="[[_constants.PrimaryTabs.FILES]]">Files</paper-tab>
+ <paper-tab data-name$="[[_constants.PrimaryTab.FILES]]">Files</paper-tab>
+ <paper-tab
+ data-name$="[[_constants.PrimaryTab.COMMENT_THREADS]]"
+ class="commentThreads"
+ >
+ <gr-tooltip-content
+ has-tooltip=""
+ title$="[[_computeTotalCommentCounts(_change.unresolved_comment_count, _changeComments)]]"
+ >
+ <span>Comments</span></gr-tooltip-content
+ >
+ </paper-tab>
<template
is="dom-repeat"
items="[[_dynamicTabHeaderEndpoints]]"
@@ -566,14 +577,14 @@
</gr-endpoint-decorator>
</paper-tab>
</template>
- <paper-tab data-name$="[[_constants.PrimaryTabs.FINDINGS]]">
+ <paper-tab data-name$="[[_constants.PrimaryTab.FINDINGS]]">
Findings
</paper-tab>
</paper-tabs>
<section class="patchInfo">
<div
- hidden$="[[!_isTabActive(_constants.PrimaryTabs.FILES, _activeTabs)]]"
+ hidden$="[[!_isTabActive(_constants.PrimaryTab.FILES, _activeTabs)]]"
>
<gr-file-list-header
id="fileListHeader"
@@ -626,10 +637,22 @@
>
</gr-file-list>
</div>
-
<template
is="dom-if"
- if="[[_isTabActive(_constants.PrimaryTabs.FINDINGS, _activeTabs)]]"
+ if="[[_isTabActive(_constants.PrimaryTab.COMMENT_THREADS, _activeTabs)]]"
+ >
+ <gr-thread-list
+ threads="[[_commentThreads]]"
+ change="[[_change]]"
+ change-num="[[_changeNum]]"
+ logged-in="[[_loggedIn]]"
+ only-show-robot-comments-with-human-reply=""
+ on-thread-list-modified="_handleReloadDiffComments"
+ ></gr-thread-list>
+ </template>
+ <template
+ is="dom-if"
+ if="[[_isTabActive(_constants.PrimaryTab.FINDINGS, _activeTabs)]]"
>
<gr-dropdown-list
class="patch-set-dropdown"
@@ -679,27 +702,16 @@
<paper-tabs id="secondaryTabs" on-selected-changed="_setActiveSecondaryTab">
<paper-tab
- data-name$="[[_constants.SecondaryTabs.CHANGE_LOG]]"
+ data-name$="[[_constants.SecondaryTab.CHANGE_LOG]]"
class="changeLog"
>
Change Log
</paper-tab>
- <paper-tab
- data-name$="[[_constants.SecondaryTabs.COMMENT_THREADS]]"
- class="commentThreads"
- >
- <gr-tooltip-content
- has-tooltip=""
- title$="[[_computeTotalCommentCounts(_change.unresolved_comment_count, _changeComments)]]"
- >
- <span>Comment Threads</span></gr-tooltip-content
- >
- </paper-tab>
</paper-tabs>
<section class="changeLog">
<template
is="dom-if"
- if="[[_isTabActive(_constants.SecondaryTabs.CHANGE_LOG, _activeTabs)]]"
+ if="[[_isTabActive(_constants.SecondaryTab.CHANGE_LOG, _activeTabs)]]"
>
<template is="dom-if" if="[[!_isChangeLogExperimentEnabled()]]">
<gr-messages-list
@@ -718,6 +730,7 @@
<template is="dom-if" if="[[_isChangeLogExperimentEnabled()]]">
<gr-messages-list-experimental
class="hideOnMobileOverlay"
+ change="[[_change]]"
change-num="[[_changeNum]]"
labels="[[_change.labels]]"
messages="[[_change.messages]]"
@@ -730,19 +743,6 @@
></gr-messages-list-experimental>
</template>
</template>
- <template
- is="dom-if"
- if="[[_isTabActive(_constants.SecondaryTabs.COMMENT_THREADS, _activeTabs)]]"
- >
- <gr-thread-list
- threads="[[_commentThreads]]"
- change="[[_change]]"
- change-num="[[_changeNum]]"
- logged-in="[[_loggedIn]]"
- only-show-robot-comments-with-human-reply=""
- on-thread-list-modified="_handleReloadDiffComments"
- ></gr-thread-list>
- </template>
</section>
</div>
@@ -801,5 +801,4 @@
<gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-comment-api id="commentAPI"></gr-comment-api>
- <gr-reporting id="reporting"></gr-reporting>
`;
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.js
similarity index 94%
rename from polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
rename to polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.js
index 62336e0..1895064 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.js
@@ -1,48 +1,24 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2015 The Android Open Source Project
+/**
+ * @license
+ * Copyright (C) 2015 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.
+ */
-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">
-<meta charset="utf-8">
-<title>gr-change-view</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-<script src="/node_modules/page/page.js"></script>
-
-<test-fixture id="basic">
- <template>
- <gr-change-view></gr-change-view>
- </template>
-</test-fixture>
-
-<test-fixture id="blank">
- <template>
- <div></div>
- </template>
-</test-fixture>
-
-<script type="module">
-import '../../../test/common-test-setup.js';
+import '../../../test/common-test-setup-karma.js';
import '../../edit/gr-edit-constants.js';
import './gr-change-view.js';
-import {PrimaryTabs, SecondaryTabs} from '../../../constants/constants.js';
+import {PrimaryTab, SecondaryTab, ChangeStatus} from '../../../constants/constants.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {KeyboardShortcutBinder} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
@@ -53,7 +29,10 @@
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
+import 'lodash/lodash.js';
+
const pluginApi = _testOnly_initGerritPluginApi();
+const fixture = fixtureFromElement('gr-change-view');
suite('gr-change-view tests', () => {
const kb = KeyboardShortcutBinder;
@@ -76,6 +55,7 @@
const ROBOT_COMMENTS_LIMIT = 10;
+ // TODO: should have a mock service to generate VALID fake data
const THREADS = [
{
comments: [
@@ -88,7 +68,7 @@
},
patch_set: 2,
robot_id: 'rb1',
- id: 'ecf9fa_fe1a5f62',
+ id: 'ecf0b9fa_fe1a5f62',
line: 5,
updated: '2018-02-08 18:49:18.000000000',
message: 'test',
@@ -102,7 +82,7 @@
username: 'user',
},
patch_set: 4,
- id: 'ecf0b9fa_fe1a5f62',
+ id: 'ecf0b9fa_fe1a5f62_1',
line: 5,
updated: '2018-02-08 18:49:18.000000000',
message: 'test',
@@ -313,7 +293,7 @@
getDiffDrafts() { return Promise.resolve({}); },
_fetchSharedCacheURL() { return Promise.resolve({}); },
});
- element = fixture('basic');
+ element = fixture.instantiate();
sandbox.stub(element.$.actions, 'reload').returns(Promise.resolve());
pluginLoader.loadPlugins([]);
pluginApi.install(
@@ -367,9 +347,9 @@
assert(element._dynamicTabHeaderEndpoints.includes(
'change-view-tab-header-url'));
const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- // 3 Tabs are : Files, Plugin, Findings
- assert.equal(paperTabs.querySelectorAll('paper-tab').length, 3);
- assert.equal(paperTabs.querySelectorAll('paper-tab')[1].dataset.name,
+ // 4 Tabs are : Files, Comment Threads, Plugin, Findings
+ assert.equal(paperTabs.querySelectorAll('paper-tab').length, 4);
+ assert.equal(paperTabs.querySelectorAll('paper-tab')[2].dataset.name,
'change-view-tab-header-url');
});
@@ -391,9 +371,9 @@
});
test('param change should switch primary tab correctly', done => {
- assert.equal(element._activeTabs[0], PrimaryTabs.FILES);
+ assert.equal(element._activeTabs[0], PrimaryTab.FILES);
const queryMap = new Map();
- queryMap.set('tab', PrimaryTabs.FINDINGS);
+ queryMap.set('tab', PrimaryTab.FINDINGS);
// view is required
element.params = Object.assign(
{
@@ -401,13 +381,13 @@
},
element.params, {queryMap});
flush(() => {
- assert.equal(element._activeTabs[0], PrimaryTabs.FINDINGS);
+ assert.equal(element._activeTabs[0], PrimaryTab.FINDINGS);
done();
});
});
test('invalid param change should not switch primary tab', done => {
- assert.equal(element._activeTabs[0], PrimaryTabs.FILES);
+ assert.equal(element._activeTabs[0], PrimaryTab.FILES);
const queryMap = new Map();
queryMap.set('tab', 'random');
// view is required
@@ -417,14 +397,14 @@
},
element.params, {queryMap});
flush(() => {
- assert.equal(element._activeTabs[0], PrimaryTabs.FILES);
+ assert.equal(element._activeTabs[0], PrimaryTab.FILES);
done();
});
});
test('switching tab sets _selectedTabPluginEndpoint', done => {
const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[1]);
+ MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[2]);
flush(() => {
assert.equal(element._selectedTabPluginEndpoint,
'change-view-tab-content-url');
@@ -714,6 +694,56 @@
});
});
+ suite('_recomputeComments', () => {
+ setup(() => {
+ // Fake computeDraftCount as its required for ChangeComments,
+ // see gr-comment-api#reloadDrafts.
+ sandbox.stub(element.$.commentAPI, 'reloadDrafts')
+ .returns(Promise.resolve({
+ drafts: {},
+ getAllThreadsForChange: () => THREADS,
+ computeDraftCount: () => 0,
+ }));
+ });
+
+ test('draft threads should be a new copy with correct states', done => {
+ element.$.fileList.dispatchEvent(
+ new CustomEvent('reload-drafts', {
+ detail: {
+ resolve: () => {
+ assert.equal(element._draftCommentThreads.length, 2);
+ assert.equal(
+ element._draftCommentThreads[0].rootId,
+ THREADS[0].rootId
+ );
+ assert.notEqual(
+ element._draftCommentThreads[0].comments,
+ THREADS[0].comments
+ );
+ assert.notEqual(
+ element._draftCommentThreads[0].comments[0],
+ THREADS[0].comments[0]
+ );
+ assert.isTrue(
+ element._draftCommentThreads[0]
+ .comments
+ .slice(0, 2)
+ .every(c => c.collapsed === true)
+ );
+
+ assert.isTrue(
+ element._draftCommentThreads[0]
+ .comments[2]
+ .collapsed === false
+ );
+ done();
+ },
+ },
+ composed: true, bubbles: true,
+ }));
+ });
+ });
+
test('diff comments modified', () => {
sandbox.spy(element, '_handleReloadCommentThreads');
return element._reloadComments().then(() => {
@@ -727,7 +757,7 @@
test('thread list modified', () => {
sandbox.spy(element, '_handleReloadDiffComments');
- element._activeTabs = [PrimaryTabs.FILES, SecondaryTabs.COMMENT_THREADS];
+ element._activeTabs = [PrimaryTab.COMMENT_THREADS, SecondaryTab.CHANGE_LOG];
flushAsynchronousOperations();
return element._reloadComments().then(() => {
@@ -791,49 +821,8 @@
element.params = {view: 'change', changeNum: '1'};
});
- test('tab switch works correctly', done => {
- assert.isTrue(element._paramsChanged.called);
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
-
- const commentTab = element.shadowRoot.querySelector(
- 'paper-tab.commentThreads'
- );
- // Switch to comment thread tab
- MockInteractions.tap(commentTab);
- assert.equal(element._activeTabs[1], SecondaryTabs.COMMENT_THREADS);
-
- // Switch back to 'Change Log' tab
- element._paramsChanged(element.params);
- flush(() => {
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
- done();
- });
- });
-
- test('show-secondary-tab event works', () => {
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
- // Switch to comment thread tab
- element.fire('show-secondary-tab', {tab: SecondaryTabs.COMMENT_THREADS});
- assert.equal(element._activeTabs[1], SecondaryTabs.COMMENT_THREADS);
- });
-
- test('param change should switched secondary tab correctly', done => {
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
- const queryMap = new Map();
- queryMap.set('secondaryTab', SecondaryTabs.COMMENT_THREADS);
- // view is required
- element.params = Object.assign(
- {view: GerritNav.View.CHANGE},
- element.params, {queryMap}
- );
- flush(() => {
- assert.equal(element._activeTabs[1], SecondaryTabs.COMMENT_THREADS);
- done();
- });
- });
-
test('invalid secondaryTab should not switch tab', done => {
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
+ assert.equal(element._activeTabs[1], SecondaryTab.CHANGE_LOG);
const queryMap = new Map();
queryMap.set('secondaryTab', 'random');
// view is required
@@ -841,7 +830,7 @@
view: GerritNav.View.CHANGE,
}, element.params, {queryMap});
flush(() => {
- assert.equal(element._activeTabs[1], SecondaryTabs.CHANGE_LOG);
+ assert.equal(element._activeTabs[1], SecondaryTab.CHANGE_LOG);
done();
});
});
@@ -862,7 +851,7 @@
};
element._commentThreads = THREADS;
const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
- MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[2]);
+ MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[3]);
flush(() => {
done();
});
@@ -1009,7 +998,7 @@
commitMessage = 'CC=test@google.com';
result = element._prepareCommitMsgForLinkify(commitMessage);
assert.equal(result, 'CC=\u200Btest@google.com');
- }),
+ });
test('_isSubmitEnabled', () => {
assert.isFalse(element._isSubmitEnabled({}));
@@ -1319,7 +1308,7 @@
test('show commit message edit button', () => {
const _change = {
- status: element.ChangeStatus.MERGED,
+ status: ChangeStatus.MERGED,
};
assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
assert.isTrue(element._computeHideEditCommitMessage(true, true, {}));
@@ -1600,7 +1589,7 @@
rev2: {_number: 2, commit: {parents: []}},
},
current_revision: 'rev1',
- status: element.ChangeStatus.MERGED,
+ status: ChangeStatus.MERGED,
labels: {},
actions: {},
};
@@ -1894,7 +1883,7 @@
sandbox.stub(element, 'fetchChangeUpdates')
.returns(Promise.resolve({
isLatest: true,
- newStatus: element.ChangeStatus.MERGED,
+ newStatus: ChangeStatus.MERGED,
}));
element.addEventListener('show-alert', e => {
assert.equal(e.detail.message, 'This change has been merged');
@@ -2251,7 +2240,7 @@
test('merged change', () => {
element._mergeable = null;
- element._change.status = element.ChangeStatus.MERGED;
+ element._change.status = ChangeStatus.MERGED;
return element._getMergeability().then(() => {
assert.isFalse(element._mergeable);
assert.isFalse(getMergeableStub.called);
@@ -2260,7 +2249,7 @@
test('abandoned change', () => {
element._mergeable = null;
- element._change.status = element.ChangeStatus.ABANDONED;
+ element._change.status = ChangeStatus.ABANDONED;
return element._getMergeability().then(() => {
assert.isFalse(element._mergeable);
assert.isFalse(getMergeableStub.called);
@@ -2319,9 +2308,9 @@
test('don\'t report changedDisplayed on reply', done => {
const changeDisplayStub =
- sandbox.stub(element.$.reporting, 'changeDisplayed');
+ sandbox.stub(element.reporting, 'changeDisplayed');
const changeFullyLoadedStub =
- sandbox.stub(element.$.reporting, 'changeFullyLoaded');
+ sandbox.stub(element.reporting, 'changeFullyLoaded');
element._handleReplySent();
flush(() => {
assert.isFalse(changeDisplayStub.called);
@@ -2332,9 +2321,9 @@
test('report changedDisplayed on _paramsChanged', done => {
const changeDisplayStub =
- sandbox.stub(element.$.reporting, 'changeDisplayed');
+ sandbox.stub(element.reporting, 'changeDisplayed');
const changeFullyLoadedStub =
- sandbox.stub(element.$.reporting, 'changeFullyLoaded');
+ sandbox.stub(element.reporting, 'changeFullyLoaded');
element._paramsChanged({
view: GerritNav.View.CHANGE,
changeNum: 101,
@@ -2348,4 +2337,3 @@
});
});
});
-</script>
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index 7ca9d6b..576b8bd 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -23,8 +23,6 @@
from HTML and may be out of place here. Review them and
then delete this comment!
*/
-
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-formatted-text/gr-formatted-text.js';
import '../../../styles/shared-styles.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -38,7 +36,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCommentList extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_html.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_html.js
index 60b83ee..2811828 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_html.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_html.js
@@ -34,6 +34,9 @@
min-width: 135px;
text-align: right;
}
+ .patchset-level-comment-text {
+ margin-right: var(--spacing-m);
+ }
.message {
flex: 1;
--gr-formatted-text-prose-max-width: 80ch;
@@ -55,9 +58,13 @@
as="file"
>
<div class="file">
- <a class="fileLink" href="[[_computeDiffURL(file, changeNum, comments)]]"
- >[[computeDisplayPath(file)]]</a
- >
+ <template is="dom-if" if="[[!shouldHideFile(file)]]">
+ <a
+ class="fileLink"
+ href="[[_computeDiffURL(file, changeNum, comments)]]"
+ >[[computeDisplayPath(file)]]
+ </a>
+ </template>
</div>
<template
is="dom-repeat"
@@ -65,18 +72,25 @@
as="comment"
>
<div class="container">
- <a
- class="lineNum"
- href$="[[_computeDiffLineURL(file, changeNum, comment.patch_set, comment)]]"
- >
- <span hidden$="[[!comment.line]]">
- <span>[[_computePatchDisplayName(comment)]]</span>
- Line <span>[[comment.line]]</span>
+ <template is="dom-if" if="[[shouldHideFile(file)]]">
+ <span class="patchset-level-comment-text">
+ Patchset Comment:
</span>
- <span hidden$="[[comment.line]]">
- File comment:
- </span>
- </a>
+ </template>
+ <template is="dom-if" if="[[!shouldHideFile(file)]]">
+ <a
+ class="lineNum"
+ href$="[[_computeDiffLineURL(file, changeNum, comment.patch_set, comment)]]"
+ >
+ <span hidden$="[[!comment.line]]">
+ <span>[[_computePatchDisplayName(comment)]]</span>
+ Line <span>[[comment.line]]</span>
+ </span>
+ <span hidden$="[[comment.line]]">
+ File comment:
+ </span>
+ </a>
+ </template>
<gr-formatted-text
class="message"
no-trailing-margin=""
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
index 4dba3af..052189e 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-copy-clipboard/gr-copy-clipboard.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -24,7 +22,7 @@
import {htmlTemplate} from './gr-commit-info_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCommitInfo extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
index d28e2b7..ada7dae 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -27,7 +25,7 @@
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmAbandonDialog extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
index 8010814..c1e1165 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
@@ -61,7 +61,6 @@
assert.isTrue(confirmHandler.calledOnce);
assert.isTrue(element._handleConfirmTap.called);
assert.isTrue(element._confirm.called);
- assert.isTrue(element._confirm.called);
assert.isTrue(element._confirm.calledOnce);
});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
index 480e6cf..34a3dcc 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-dialog/gr-dialog.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -24,7 +22,7 @@
import {htmlTemplate} from './gr-confirm-cherrypick-conflict-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmCherrypickConflictDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
index 2802046..d2dcbca 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
@@ -14,20 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '@polymer/iron-input/iron-input.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-dialog/gr-dialog.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-confirm-cherrypick-dialog_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {appContext} from '../../../services/app-context.js';
const SUGGESTIONS_LIMIT = 15;
const CHANGE_SUBJECT_LIMIT = 50;
@@ -37,7 +35,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmCherrypickDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -97,6 +95,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
static get observers() {
return [
'_computeMessage(changeStatus, commitNum, commitMessage)',
@@ -260,7 +263,7 @@
e.preventDefault();
e.stopPropagation();
if (this._cherryPickType === CHERRY_PICK_TYPES.TOPIC) {
- this.$.reporting.reportInteraction('cherry-pick-topic-clicked');
+ this.reporting.reportInteraction('cherry-pick-topic-clicked');
this._handleCherryPickTopic();
return;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.js
index aeb8061..eaf9cc8 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.js
@@ -212,9 +212,5 @@
</template>
</div>
</gr-dialog>
- <gr-reporting
- id="reporting"
- category="confirm-cherry-pick-dialog"
- ></gr-reporting>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
index 25beb2d..f2ea45d 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
@@ -14,9 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-dialog/gr-dialog.js';
@@ -31,7 +28,7 @@
const SUGGESTIONS_LIMIT = 15;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmMoveDialog extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
index e451034..0a45de2 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -25,7 +23,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-confirm-rebase-dialog_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrConfirmRebaseDialog extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
index 6eb4c82..9489b94 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
@@ -14,9 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
@@ -37,7 +34,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmRevertDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
index 212f909..c8e14f7 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.js
@@ -14,9 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
@@ -30,7 +27,7 @@
const CHANGE_SUBJECT_LIMIT = 50;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmRevertSubmissionDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
index 5d599b7..42afcc2 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-icon/iron-icon.js';
import '../../shared/gr-icons/gr-icons.js';
import '../../shared/gr-dialog/gr-dialog.js';
@@ -28,7 +26,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-confirm-submit-dialog_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrConfirmSubmitDialog extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index 4c457a1..6e22374 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-download-commands/gr-download-commands.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -27,7 +25,7 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDownloadDialog extends mixinBehaviors( [
PatchSetBehavior,
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 73c6721..1f9ca20 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
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../diff/gr-diff-mode-selector/gr-diff-mode-selector.js';
import '../../diff/gr-patch-range-select/gr-patch-range-select.js';
@@ -43,7 +41,7 @@
const MERGED_STATUS = 'MERGED';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrFileListHeader extends mixinBehaviors( [
PatchSetBehavior,
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index eb85cd7..12b5aad 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../diff/gr-diff-cursor/gr-diff-cursor.js';
import '../../diff/gr-diff-host/gr-diff-host.js';
import '../../diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.js';
@@ -46,6 +43,8 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {pluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
+import {appContext} from '../../../services/app-context.js';
+import {SpecialFilePath} from '../../../constants/constants.js';
// Maximum length for patch set descriptions.
const PATCH_DESC_MAX_LENGTH = 500;
@@ -87,17 +86,7 @@
*/
/**
- * Type for FileData
- *
- * This contains minimal info required about the file to get comments for
- *
- * @typedef {Object} FileData
- * @property {string} path
- * @property {?string} oldPath
- */
-
-/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrFileList extends mixinBehaviors( [
AsyncForeachBehavior,
@@ -206,7 +195,7 @@
*/
_reportinShownFilesIncrement: Number,
- /** @type {!Array<FileData>} */
+ /** @type {!Array<Gerrit.FileRange>} */
_expandedFiles: {
type: Array,
value() { return []; },
@@ -290,6 +279,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -375,14 +369,14 @@
return Promise.all(promises).then(() => {
this._loading = false;
this._detectChromiteButler();
- this.$.reporting.fileListDisplayed();
+ this.reporting.fileListDisplayed();
});
}
_detectChromiteButler() {
const hasButler = !!document.getElementById('butler-suggested-owners');
if (hasButler) {
- this.$.reporting.reportExtension('butler');
+ this.reporting.reportExtension('butler');
}
}
@@ -444,13 +438,13 @@
}
_toggleFileExpandedByIndex(index) {
- this._toggleFileExpanded(this._computeFileData(this._files[index]));
+ this._toggleFileExpanded(this._computeFileRange(this._files[index]));
}
_updateDiffPreferences() {
if (!this.diffs.length) { return; }
// Re-render all expanded diffs sequentially.
- this.$.reporting.time(EXPAND_ALL_TIMING_LABEL);
+ this.reporting.time(EXPAND_ALL_TIMING_LABEL);
this._renderInOrder(this._expandedFiles, this.diffs,
this._expandedFiles.length);
}
@@ -472,7 +466,7 @@
for (let i = 0; i < this._shownFiles.length; i++) {
path = this._shownFiles[i].__path;
if (!this._expandedFiles.some(f => f.path === path)) {
- newFiles.push(this._computeFileData(this._shownFiles[i]));
+ newFiles.push(this._computeFileRange(this._shownFiles[i]));
}
}
@@ -684,17 +678,17 @@
}
/**
- * Generates file data from file info object.
+ * Generates file range from file info object.
*
* @param {FileInfo} file
- * @returns {FileData}
+ * @returns {Gerrit.FileRange}
*/
- _computeFileData(file) {
+ _computeFileRange(file) {
const fileData = {
path: file.__path,
};
if (file.old_path) {
- fileData.oldPath = file.old_path;
+ fileData.basePath = file.old_path;
}
return fileData;
}
@@ -910,7 +904,7 @@
.some(arg => arg === undefined)) {
return;
}
- if (editMode && path !== this.MERGE_LIST_PATH) {
+ if (editMode && path !== SpecialFilePath.MERGE_LIST) {
return GerritNav.getEditUrlForDiff(change, path, patchRange.patchNum,
patchRange.basePatchNum);
}
@@ -953,12 +947,18 @@
if (baseClass) {
classes.push(baseClass);
}
- if (path === this.COMMIT_MESSAGE_PATH || path === this.MERGE_LIST_PATH) {
+ if (path === SpecialFilePath.COMMIT_MESSAGE ||
+ path === SpecialFilePath.MERGE_LIST) {
classes.push('invisible');
}
return classes.join(' ');
}
+ _computeStatusClass(file) {
+ const classStr = this._computeClass('status', file.__path);
+ return `${classStr} ${this._computeFileStatus(file.status)}`;
+ }
+
_computePathClass(path, expandedFilesRecord) {
return this._isFileExpanded(path, expandedFilesRecord) ? 'expanded' : '';
}
@@ -985,10 +985,7 @@
const commentedPaths = changeComments.getPaths(patchRange);
const files = Object.assign({}, filesByPath);
- Object.keys(commentedPaths).forEach(commentedPath => {
- if (files.hasOwnProperty(commentedPath)) { return; }
- files[commentedPath] = {status: 'U'};
- });
+ this.addUnmodifiedFiles(files, commentedPaths);
const reviewedSet = new Set(reviewed || []);
for (const filePath in files) {
if (!files.hasOwnProperty(filePath)) { continue; }
@@ -1016,7 +1013,7 @@
// Start the timer for the rendering work hwere because this is where the
// _shownFiles property is being set, and _shownFiles is used in the
// dom-repeat binding.
- this.$.reporting.time(RENDER_TIMING_LABEL);
+ this.reporting.time(RENDER_TIMING_LABEL);
// How many more files are being shown (if it's an increase).
this._reportinShownFilesIncrement =
@@ -1034,9 +1031,8 @@
_filesChanged() {
if (this._files && this._files.length > 0) {
flush();
- const files = Array.from(
+ this.$.fileCursor.stops = Array.from(
dom(this.root).querySelectorAll('.file-row'));
- this.$.fileCursor.stops = files;
this.$.fileCursor.setCursorAtIndex(this.selectedIndex, true);
}
}
@@ -1141,7 +1137,7 @@
// Required so that the newly created diff view is included in this.diffs.
flush();
- this.$.reporting.time(EXPAND_ALL_TIMING_LABEL);
+ this.reporting.time(EXPAND_ALL_TIMING_LABEL);
if (newFiles.length) {
this._renderInOrder(newFiles, this.diffs, newFiles.length);
@@ -1161,9 +1157,9 @@
/**
* Given an array of paths and a NodeList of diff elements, render the diff
* for each path in order, awaiting the previous render to complete before
- * continung.
+ * continuing.
*
- * @param {!Array<FileData>} files
+ * @param {!Array<Gerrit.FileRange>} files
* @param {!NodeList<!Object>} diffElements (GrDiffHostElement)
* @param {number} initialCount The total number of paths in the pass. This
* is used to generate log messages.
@@ -1200,9 +1196,17 @@
this._cancelForEachDiff = null;
this._nextRenderParams = null;
console.log('Finished expanding', initialCount, 'diff(s)');
- this.$.reporting.timeEndWithAverage(EXPAND_ALL_TIMING_LABEL,
+ this.reporting.timeEndWithAverage(EXPAND_ALL_TIMING_LABEL,
EXPAND_ALL_AVG_TIMING_LABEL, initialCount);
- this.$.diffCursor.handleDiffUpdate();
+ /* Block diff cursor from auto scrolling after files are done rendering.
+ * This prevents the bug where the screen jumps to the first diff chunk
+ * after files are done being rendered after the user has already begun
+ * scrolling.
+ * This also however results in the fact that the cursor does not auto
+ * focus on the first diff chunk on a small screen. This is however, a use
+ * case we are willing to not support for now.
+ */
+ this.$.diffCursor.reInitAndUpdateStops();
}));
}
@@ -1262,7 +1266,6 @@
c, {__commentSide: threadEl.commentSide}
));
flush();
- return;
}
_handleEscKey(e) {
@@ -1307,7 +1310,8 @@
* @return {boolean}
*/
_showBarsForPath(path) {
- return path !== this.COMMIT_MESSAGE_PATH && path !== this.MERGE_LIST_PATH;
+ return path !== SpecialFilePath.COMMIT_MESSAGE &&
+ path !== SpecialFilePath.MERGE_LIST;
}
/**
@@ -1421,7 +1425,7 @@
/**
* Shows registered dynamic columns iff the 'header', 'content' and
- * 'summary' endpoints are regiestered the exact same number of times.
+ * 'summary' endpoints are registered the exact same number of times.
* Ideally, there should be a better way to enforce the expectation of the
* dependencies between dynamic endpoints.
*/
@@ -1452,7 +1456,7 @@
_reportRenderedRow(index) {
if (index === this._shownFiles.length - 1) {
this.async(() => {
- this.$.reporting.timeEndWithAverage(RENDER_TIMING_LABEL,
+ this.reporting.timeEndWithAverage(RENDER_TIMING_LABEL,
RENDER_AVG_TIMING_LABEL, this._reportinShownFilesIncrement);
}, 1);
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.js
index a9a785e..df6f43d 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.js
@@ -26,8 +26,7 @@
border-top: 1px solid var(--border-color);
display: flex;
min-height: calc(var(--line-height-normal) + 2 * var(--spacing-s));
- padding: var(--spacing-xs) var(--spacing-l) var(--spacing-xs)
- calc(var(--spacing-l) - 0.35rem);
+ padding: var(--spacing-xs) var(--spacing-l);
}
:host(.loading) .row {
opacity: 0.5;
@@ -62,12 +61,31 @@
align-items: center;
display: inline-flex;
}
- .reviewed,
- .status {
+ .reviewed {
display: inline-block;
text-align: left;
width: 1.5em;
}
+ .status {
+ display: inline-block;
+ border-radius: var(--border-radius);
+ margin-left: var(--spacing-s);
+ padding: 0 var(--spacing-m);
+ color: var(--primary-text-color);
+ font-size: var(--font-size-small);
+ background-color: var(--dark-add-highlight-color);
+ }
+ .status.M {
+ display: none;
+ }
+ .status.D,
+ .status.R,
+ .status.W {
+ background-color: var(--dark-remove-highlight-color);
+ }
+ .status.U {
+ background-color: var(--comment-background-color);
+ }
.file-row {
cursor: pointer;
}
@@ -221,7 +239,8 @@
padding: var(--spacing-s) 0;
text-decoration: none;
}
- .pathLink:hover {
+ .pathLink:hover span.fullFileName,
+ .pathLink:hover span.truncatedFileName {
text-decoration: underline;
}
@@ -231,7 +250,6 @@
display: inline-block;
visibility: hidden;
vertical-align: bottom;
- text-decoration: none;
--gr-button: {
padding: 0px;
}
@@ -277,7 +295,6 @@
</style>
<div id="container" on-click="_handleFileListClick">
<div class="header-row row">
- <div class="status"></div>
<div class="path">File</div>
<div class="comments">Comments</div>
<div class="sizeBars">Size</div>
@@ -310,17 +327,9 @@
<div class="stickyArea">
<div
class$="file-row row [[_computePathClass(file.__path, _expandedFiles.*)]]"
- data-file$="[[_computeFileData(file)]]"
+ data-file$="[[_computeFileRange(file)]]"
tabindex="-1"
>
- <div
- class$="[[_computeClass('status', file.__path)]]"
- tabindex="0"
- title$="[[_computeFileStatusLabel(file.status)]]"
- aria-label$="[[_computeFileStatusLabel(file.status)]]"
- >
- [[_computeFileStatus(file.status)]]
- </div>
<!-- TODO: Remove data-url as it appears its not used -->
<span
data-url="[[_computeDiffURL(change, patchRange, file.__path, editMode)]]"
@@ -342,6 +351,14 @@
>
[[computeTruncatedPath(file.__path)]]
</span>
+ <span
+ class$="[[_computeStatusClass(file)]]"
+ tabindex="0"
+ title$="[[_computeFileStatusLabel(file.status)]]"
+ aria-label$="[[_computeFileStatusLabel(file.status)]]"
+ >
+ [[_computeFileStatusLabel(file.status)]]
+ </span>
<gr-copy-clipboard
hide-input=""
text="[[file.__path]]"
@@ -490,6 +507,7 @@
hidden="[[!_isFileExpanded(file.__path, _expandedFiles.*)]]"
change-num="[[changeNum]]"
patch-range="[[patchRange]]"
+ file="[[_computeFileRange(file)]]"
path="[[file.__path]]"
prefs="[[diffPrefs]]"
project-name="[[change.project]]"
@@ -583,9 +601,8 @@
<gr-diff-cursor id="diffCursor"></gr-diff-cursor>
<gr-cursor-manager
id="fileCursor"
- scroll-behavior="keep-visible"
+ scroll-mode="keep-visible"
focus-on-move=""
cursor-target-class="selected"
></gr-cursor-manager>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 32945e4..f038f6c 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -45,9 +45,9 @@
<script type="module">
import '../../../test/common-test-setup.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
-import {getMockDiffResponse} from '../../../test/mock-diff-response.js';
+import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-file-list.js';
-import '../../diff/gr-comment-api/gr-comment-api-mock_test.js';
+import '../../../test/mocks/comment-api.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {KeyboardShortcutBinder} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {GrFileListConstants} from '../gr-file-list-constants.js';
@@ -1641,7 +1641,7 @@
assert.isTrue(diffStops[10].classList.contains('target-row'));
assert.isFalse(diffStops[11].classList.contains('target-row'));
- // The file cusor is now at 1.
+ // The file cursor is now at 1.
assert.equal(element.$.fileCursor.index, 1);
MockInteractions.keyUpOn(element, 73, null, 'i');
flushAsynchronousOperations();
@@ -1652,7 +1652,7 @@
const diffStopsFirst = diffs[0].getCursorStops();
const diffStopsSecond = diffs[1].getCursorStops();
- // The line on the first diff is stil selected
+ // The line on the first diff is still selected
assert.isTrue(diffStopsFirst[10].classList.contains('target-row'));
assert.isFalse(diffStopsSecond[10].classList.contains('target-row'));
});
@@ -1683,7 +1683,7 @@
assert.isFalse(diffStops[10].classList.contains('target-row'));
assert.isTrue(diffStops[11].classList.contains('target-row'));
- // The file cusor is still at 0.
+ // The file cursor is still at 0.
assert.equal(element.$.fileCursor.index, 0);
});
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
index f79dba3..132cd16 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -26,7 +24,7 @@
import {htmlTemplate} from './gr-included-in-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrIncludedInDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
index 8541840..5b9730b 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-selector/iron-selector.js';
import '../../shared/gr-button/gr-button.js';
import '../../../styles/gr-voting-styles.js';
@@ -25,7 +23,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-label-score-row_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLabelScoreRow extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
index 6e0a90d..0fc6e4c 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
@@ -268,7 +268,7 @@
assert.isTrue(element.$.labelSelector.hidden);
});
- test('asymetrical labels', done => {
+ test('asymmetrical labels', done => {
element.permittedLabels = {
'Code-Review': [
'-2',
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
index 2d6825b..35ccc3c 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-label-score-row/gr-label-score-row.js';
import '../../../styles/shared-styles.js';
@@ -24,7 +22,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-label-scores_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLabelScores extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index 906ed34..3dda25b 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-icon/iron-icon.js';
import '../../shared/gr-account-label/gr-account-label.js';
@@ -26,16 +25,19 @@
import '../../../styles/shared-styles.js';
import '../../../styles/gr-voting-styles.js';
import '../gr-comment-list/gr-comment-list.js';
+import {appContext} from '../../../services/app-context.js';
+import {ExperimentIds} from '../../../services/flags.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-message_html.js';
+import {SpecialFilePath} from '../../../constants/constants.js';
const PATCH_SET_PREFIX_PATTERN = /^Patch Set \d+:\s*(.*)/;
const LABEL_TITLE_SCORE_PATTERN = /^(-?)([A-Za-z0-9-]+?)([+-]\d+)?$/;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrMessage extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -62,6 +64,8 @@
static get properties() {
return {
+ /** @type {?} */
+ change: Object,
changeNum: Number,
/** @type {?} */
message: Object,
@@ -69,6 +73,19 @@
type: Object,
computed: '_computeAuthor(message)',
},
+ /**
+ * Used in cleaner_changelog experiment
+ *
+ * @type {Array} - array of threads attached to the message
+ */
+ commentThreads: {
+ type: Array,
+ },
+ /**
+ * TODO(taoalpha): remove once the change log experiment is launched
+ *
+ * @type {Object} - a map on file and comments on it
+ */
comments: {
type: Object,
},
@@ -122,11 +139,13 @@
_messageContentCollapsed: {
type: String,
computed:
- '_computeMessageContentCollapsed(message.message, message.tag)',
+ '_computeMessageContentCollapsed(message.message, message.tag,' +
+ ' commentThreads)',
},
_commentCountText: {
type: Number,
- computed: '_computeCommentCountText(comments)',
+ computed: '_computeCommentCountText(comments, commentThreads,'
+ + ' _isCleanerLogExperimentEnabled)',
},
_loggedIn: {
type: Boolean,
@@ -140,6 +159,7 @@
type: Boolean,
value: false,
},
+ _isCleanerLogExperimentEnabled: Boolean,
};
}
@@ -149,6 +169,11 @@
];
}
+ constructor() {
+ super();
+ this.flagsService = appContext.flagsService;
+ }
+
/** @override */
created() {
super.created();
@@ -159,6 +184,8 @@
/** @override */
ready() {
super.ready();
+ this._isCleanerLogExperimentEnabled = this.flagsService
+ .isEnabled(ExperimentIds.CLEANER_CHANGELOG);
this.$.restAPI.getConfig().then(config => {
this.config = config;
});
@@ -178,30 +205,76 @@
}
}
- _computeCommentCountText(comments) {
- if (!comments) return undefined;
- let count = 0;
- for (const file in comments) {
- if (comments.hasOwnProperty(file)) {
- const commentArray = comments[file] || [];
- count += commentArray.length;
+ _computeCommentCountText(comments, threads, isCleanerLogExperimentEnabled) {
+ // TODO(taoalpha): clean up after cleaner-changelog experiment launched
+ if (isCleanerLogExperimentEnabled) {
+ if (!threads) return undefined;
+ const count = threads.length;
+ if (count === 0) {
+ return undefined;
+ } else if (count === 1) {
+ return '1 comment';
+ } else {
+ return `${count} comments`;
+ }
+ } else {
+ if (!comments) return undefined;
+ let count = 0;
+ for (const file in comments) {
+ if (comments.hasOwnProperty(file)) {
+ const commentArray = comments[file] || [];
+ count += commentArray.length;
+ }
+ }
+ if (count === 0) {
+ return undefined;
+ } else if (count === 1) {
+ return '1 comment';
+ } else {
+ return `${count} comments`;
}
}
- if (count === 0) {
- return undefined;
- } else if (count === 1) {
- return '1 comment';
- } else {
- return `${count} comments`;
- }
+ }
+
+ _onThreadListModified() {
+ // TODO(taoalpha): this won't propagate the changes to the files
+ // should consider replacing this with either top level events
+ // or gerrit level events
+
+ // emit the event so change-view can also get updated with latest changes
+ this.fire('comment-refresh');
}
_computeMessageContentExpanded(content, tag) {
return this._computeMessageContent(content, tag, true);
}
- _computeMessageContentCollapsed(content, tag) {
- return this._computeMessageContent(content, tag, false);
+ _patchsetCommentSummary(commentThreads) {
+ const id = this.message.id;
+ if (!id) return '';
+ const patchsetThreads = commentThreads.filter(thread =>
+ thread.path === SpecialFilePath.PATCHSET_LEVEL_COMMENTS);
+ for (const thread of patchsetThreads) {
+ // Find if there was a patchset level comment created through the reply
+ // dialog and use it to determine the summary
+ if (thread.comments[0].change_message_id === id) {
+ return thread.comments[0].message;
+ }
+ }
+ // Find if there is a reply to some patchset comment left
+ for (const thread of patchsetThreads) {
+ for (const comment of thread.comments) {
+ if (comment.change_message_id === id) { return comment.message; }
+ }
+ }
+ return '';
+ }
+
+ _computeMessageContentCollapsed(content, tag, commentThreads) {
+ const summary =
+ this._computeMessageContent(content, tag, false);
+ if (summary || !commentThreads) return;
+ return this._patchsetCommentSummary(commentThreads);
}
_computeMessageContent(content, tag, isExpanded) {
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.js b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.js
index 753fd38..84713db 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.js
@@ -66,6 +66,7 @@
margin: 0 -4px;
}
.collapsed gr-comment-list,
+ .collapsed gr-thread-list,
.collapsed .replyBtn,
.collapsed .deleteBtn,
.collapsed .hideOnCollapsed,
@@ -217,40 +218,56 @@
content="[[_messageContentExpanded]]"
config="[[_projectConfig.commentlinks]]"
></gr-formatted-text>
- <template is="dom-if" if="[[_messageContentExpanded]]">
- <div
- class="replyActionContainer"
- hidden$="[[!showReplyButton]]"
- hidden=""
- >
- <gr-button
- class="replyBtn"
- link=""
- small=""
- on-click="_handleReplyTap"
- >
- Reply
- </gr-button>
- <gr-button
- disabled$="[[_isDeletingChangeMsg]]"
- class="deleteBtn"
- hidden$="[[!_isAdmin]]"
+ <template is="dom-if" if="[[_expanded]]">
+ <template is="dom-if" if="[[_messageContentExpanded]]">
+ <div
+ class="replyActionContainer"
+ hidden$="[[!showReplyButton]]"
hidden=""
- link=""
- small=""
- on-click="_handleDeleteMessage"
>
- Delete
- </gr-button>
- </div>
+ <gr-button
+ class="replyBtn"
+ link=""
+ small=""
+ on-click="_handleReplyTap"
+ >
+ Reply
+ </gr-button>
+ <gr-button
+ disabled$="[[_isDeletingChangeMsg]]"
+ class="deleteBtn"
+ hidden$="[[!_isAdmin]]"
+ hidden=""
+ link=""
+ small=""
+ on-click="_handleDeleteMessage"
+ >
+ Delete
+ </gr-button>
+ </div>
+ </template>
+ <template is="dom-if" if="[[!_isCleanerLogExperimentEnabled]]">
+ <gr-comment-list
+ comments="[[comments]]"
+ change-num="[[changeNum]]"
+ patch-num="[[message._revision_number]]"
+ project-name="[[projectName]]"
+ project-config="[[_projectConfig]]"
+ ></gr-comment-list>
+ </template>
+ <template is="dom-if" if="[[_isCleanerLogExperimentEnabled]]">
+ <gr-thread-list
+ change="[[change]]"
+ hidden$="[[!commentThreads.length]]"
+ threads="[[commentThreads]]"
+ change-num="[[changeNum]]"
+ logged-in="[[_loggedIn]]"
+ hide-toggle-buttons
+ on-thread-list-modified="_onThreadListModified"
+ >
+ </gr-thread-list>
+ </template>
</template>
- <gr-comment-list
- comments="[[comments]]"
- change-num="[[changeNum]]"
- patch-num="[[message._revision_number]]"
- project-name="[[projectName]]"
- project-config="[[_projectConfig]]"
- ></gr-comment-list>
</div>
</template>
<template is="dom-if" if="[[_computeIsReviewerUpdate(message)]]">
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
index 4651e66..edcb7f6 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
@@ -62,7 +62,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'Uploaded patch set 1.',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
element.addEventListener('reply', e => {
@@ -87,7 +87,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'Uploaded patch set 1.',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
flushAsynchronousOperations();
@@ -105,7 +105,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'Uploaded patch set 1.',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
element.addEventListener('change-message-deleted', e => {
@@ -378,7 +378,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'Uploaded patch set 1.',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
flushAsynchronousOperations();
@@ -391,6 +391,65 @@
});
});
+ suite('patchset comment summary', () => {
+ setup(() => {
+ element = fixture('basic');
+ element.message = {id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3'};
+ });
+
+ test('single patchset comment posted', () => {
+ const threads = [{
+ comments: [{
+ __path: '/PATCHSET_LEVEL',
+ change_message_id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3',
+ patch_set: 1,
+ id: 'e365b138_bed65caa',
+ updated: '2020-05-15 13:35:56.000000000',
+ message: 'testing the load',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ collapsed: false,
+ }],
+ patchNum: 1,
+ path: '/PATCHSET_LEVEL',
+ rootId: 'e365b138_bed65caa',
+ }];
+ assert.equal(element._patchsetCommentSummary(threads),
+ 'testing the load');
+ });
+
+ test('single patchset comment with reply', () => {
+ const threads = [{
+ comments: [{
+ __path: '/PATCHSET_LEVEL',
+ patch_set: 1,
+ id: 'e365b138_bed65caa',
+ updated: '2020-05-15 13:35:56.000000000',
+ message: 'testing the load',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ collapsed: false,
+ }, {
+ __path: '/PATCHSET_LEVEL',
+ change_message_id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3',
+ patch_set: 1,
+ id: 'd6efcc85_4cbbb6f4',
+ in_reply_to: 'e365b138_bed65caa',
+ updated: '2020-05-15 16:55:28.000000000',
+ message: 'n',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ __draft: true,
+ collapsed: true,
+ }],
+ patchNum: 1,
+ path: '/PATCHSET_LEVEL',
+ rootId: 'e365b138_bed65caa',
+ }];
+ assert.equal(element._patchsetCommentSummary(threads), 'n');
+ });
+ });
+
suite('when logged in but not admin', () => {
setup(done => {
stub('gr-rest-api-interface', {
@@ -414,7 +473,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'Uploaded patch set 1.',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
flushAsynchronousOperations();
@@ -444,7 +503,7 @@
date: '2016-01-12 20:24:49.448000000',
message: 'not empty',
_revision_number: 1,
- expanded: false,
+ expanded: true,
};
flushAsynchronousOperations();
replyEl = element.shadowRoot.querySelector('.replyActionContainer');
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental.js
index c888fcf..ccc4a76 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental.js
@@ -14,11 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-toggle-button/paper-toggle-button.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-button/gr-button.js';
+import '../../shared/gr-icons/gr-icons.js';
import '../gr-message/gr-message.js';
import '../../../styles/shared-styles.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -28,7 +26,9 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-messages-list-experimental_html.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
+import {MessageTag} from '../../../constants/constants.js';
+import {appContext} from '../../../services/app-context.js';
/**
* The content of the enum is also used in the UI for the button text.
@@ -41,7 +41,115 @@
};
/**
- * @extends Polymer.Element
+ * Computes message author's comments for this change message. The backend
+ * sets comment.change_message_id for matching, so this computation is fairly
+ * straightforward.
+ */
+function computeThreads(message, allMessages, changeComments) {
+ if ([message, allMessages, changeComments].some(arg => arg === undefined)) {
+ return [];
+ }
+ if (message._index === undefined) {
+ return [];
+ }
+
+ return changeComments.getAllThreadsForChange().filter(
+ thread => thread.comments.map(comment => {
+ // collapse all by default
+ comment.collapsed = true;
+ return comment;
+ }).some(comment => {
+ const condition = comment.change_message_id === message.id;
+ // Since getAllThreadsForChange() always returns a new copy of
+ // all comments we can modify them here without worrying about
+ // polluting other threads.
+ comment.collapsed = !condition;
+ return condition;
+ })
+ );
+}
+
+/**
+ * If messages have the same tag, then that influences grouping and whether
+ * a message is initally hidden or not, see isImportant(). So we are applying
+ * some "magic" rules here in order to hide exactly the right messages.
+ *
+ * 1. If a message does not have a tag, but is associated with robot comments,
+ * then it gets a tag.
+ *
+ * 2. Use the same tag for some of Gerrit's standard events, if they should be
+ * considered one group, e.g. normal and wip patchset uploads.
+ *
+ * 3. Everything beyond the ~ character is cut off from the tag. That gives
+ * tools control over which messages will be hidden.
+ */
+function computeTag(message) {
+ if (!message.tag) {
+ const threads = message.commentThreads || [];
+ const comments = threads.map(
+ t => t.comments.find(c => c.change_message_id === message.id));
+ const isRobot = comments.some(c => c && !!c.robot_id);
+ return isRobot ? 'autogenerated:has-robot-comments' : undefined;
+ }
+
+ if (message.tag === MessageTag.TAG_NEW_WIP_PATCHSET) {
+ return MessageTag.TAG_NEW_PATCHSET;
+ }
+ if (message.tag === MessageTag.TAG_UNSET_ASSIGNEE) {
+ return MessageTag.TAG_SET_ASSIGNEE;
+ }
+ if (message.tag === MessageTag.TAG_UNSET_PRIVATE) {
+ return MessageTag.TAG_SET_PRIVATE;
+ }
+ if (message.tag === MessageTag.TAG_SET_WIP) {
+ return MessageTag.TAG_SET_READY;
+ }
+
+ return message.tag.replace(/~.*/, '');
+}
+
+/**
+ * Try to set a revision number that makes sense, if none is set. Just copy
+ * over the revision number of the next older message. This is mostly relevant
+ * for reviewer updates. Other messages should typically have the revision
+ * number already set.
+ */
+function computeRevision(message, allMessages) {
+ if (message._revision_number > 0) return message._revision_number;
+ let revision = 0;
+ for (const m of allMessages) {
+ if (m.date > message.date) break;
+ if (m._revision_number > revision) revision = m._revision_number;
+ }
+ return revision > 0 ? revision : undefined;
+}
+
+/**
+ * Unimportant messages are initially hidden.
+ *
+ * Human messages are always important. They have an undefined tag.
+ *
+ * Autogenerated messages are unimportant, if there is a message with the same
+ * tag and a higher revision number.
+ */
+function computeIsImportant(message, allMessages) {
+ if (!message.tag) return true;
+
+ const hasSameTag = m => m.tag === message.tag;
+ const revNumber = message._revision_number || 0;
+ const hasHigherRevisionNumber = m => m._revision_number > revNumber;
+ return !allMessages.filter(hasSameTag).some(hasHigherRevisionNumber);
+}
+
+export const TEST_ONLY = {
+ computeThreads,
+ computeTag,
+ computeRevision,
+ computeIsImportant,
+};
+
+/**
+ * @extends PolymerElement
*/
class GrMessagesListExperimental extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -54,6 +162,8 @@
static get properties() {
return {
+ /** @type {?} */
+ change: Object,
changeNum: Number,
/**
* These are just the change messages. They are combined with reviewer
@@ -95,17 +205,18 @@
computed: '_computeExpandAllTitle(_expandAllState)',
},
- _hideAutomated: {
+ _showAllActivity: {
type: Boolean,
value: false,
- observer: '_hideAutomatedChanged',
+ observer: '_observeShowAllActivity',
},
/**
* The merged array of change messages and reviewer updates.
*/
_combinedMessages: {
type: Array,
- computed: '_computeCombinedMessages(messages, reviewerUpdates)',
+ computed: '_computeCombinedMessages(messages, reviewerUpdates, '
+ + 'changeComments)',
observer: '_combinedMessagesChanged',
},
@@ -116,16 +227,21 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
scrollToMessage(messageID) {
const selector = `[data-message-id="${messageID}"]`;
const el = this.shadowRoot.querySelector(selector);
- if (!el && !this._hideAutomated) {
+ if (!el && this._showAllActivity) {
console.warn(`Failed to scroll to message: ${messageID}`);
return;
}
if (!el) {
- this._hideAutomated = false;
+ this._showAllActivity = true;
setTimeout(() => this.scrollToMessage(messageID));
return;
}
@@ -141,15 +257,7 @@
this._highlightEl(el);
}
- _isAutomated(message) {
- const isReviewerUpdate =
- !!(message.reviewer || message.type === 'REVIEWER_UPDATE');
- const isAutoGenerated =
- !!(message.tag && message.tag.startsWith('autogenerated'));
- return isReviewerUpdate || isAutoGenerated;
- }
-
- _hideAutomatedChanged(hideAutomated) {
+ _observeShowAllActivity(showAllActivity) {
// We have to call render() such that the dom-repeat filter picks up the
// change.
this.$.messageRepeat.render();
@@ -159,13 +267,14 @@
* Filter for the dom-repeat of combinedMessages.
*/
_isMessageVisible(message) {
- return !(this._hideAutomated && this._isAutomated(message));
+ return this._showAllActivity || message.isImportant;
}
/**
- * Merges change messages and reviewer updates into one array.
+ * Merges change messages and reviewer updates into one array. Also processes
+ * all messages and updates, aligns or massages some of the properties.
*/
- _computeCombinedMessages(messages, reviewerUpdates) {
+ _computeCombinedMessages(messages, reviewerUpdates, changeComments) {
messages = messages || [];
reviewerUpdates = reviewerUpdates || [];
let mi = 0;
@@ -186,8 +295,8 @@
combinedMessages = combinedMessages.concat(messages.slice(mi));
break;
}
- mDate = mDate || util.parseDate(messages[mi].date);
- rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
+ mDate = mDate || parseDate(messages[mi].date);
+ rDate = rDate || parseDate(reviewerUpdates[ri].date);
if (rDate < mDate) {
combinedMessages.push(reviewerUpdates[ri++]);
rDate = null;
@@ -200,6 +309,10 @@
if (m.expanded === undefined) {
m.expanded = false;
}
+ m.commentThreads = computeThreads(m, combinedMessages, changeComments);
+ m._revision_number = computeRevision(m, combinedMessages);
+ m.tag = computeTag(m);
+ m.isImportant = computeIsImportant(m, combinedMessages);
});
return combinedMessages;
}
@@ -228,8 +341,8 @@
_highlightEl(el) {
const highlightedEls =
dom(this.root).querySelectorAll('.highlighted');
- for (const highlighedEl of highlightedEls) {
- highlighedEl.classList.remove('highlighted');
+ for (const highlightedEl of highlightedEls) {
+ highlightedEl.classList.remove('highlighted');
}
function handleAnimationEnd() {
el.removeEventListener('animationend', handleAnimationEnd);
@@ -258,44 +371,12 @@
this.scrollToMessage(e.detail.id);
}
- _hasAutomatedMessages(messages) {
- if (!messages) { return false; }
- for (const message of messages) {
- if (this._isAutomated(message)) {
- return true;
- }
- }
- return false;
+ _isVisibleShowAllActivityToggle(messages = []) {
+ return messages.some(m => !m.isImportant);
}
- /**
- * Computes message author's file comments for change's message. The backend
- * sets comment.change_message_id for matching, so this computation is fairly
- * straightforward.
- *
- * @param {!Object} changeComments changeComment object, which includes
- * a method to get all published comments (including robot comments),
- * which returns a Hash of arrays of comments, filename as key.
- * @param {!Object} message
- * @return {!Object} Hash of arrays of comments, filename as key.
- */
- _computeCommentsForMessage(changeComments, message) {
- if ([changeComments, message].some(arg => arg === undefined)) {
- return {};
- }
- const comments = changeComments.getAllPublishedComments();
- if (message._index === undefined || !comments || !this.messages) {
- return {};
- }
- const idFilter = comment => comment.change_message_id === message.id;
-
- const msgComments = {};
- for (const file in comments) {
- if (!comments.hasOwnProperty(file)) { continue; }
- const filtered = comments[file].filter(idFilter);
- if (filtered.length) msgComments[file] = filtered;
- }
- return msgComments;
+ _computeHiddenEntriesCount(messages = []) {
+ return messages.filter(m => !m.isImportant).length;
}
/**
@@ -311,7 +392,7 @@
acc[val] = (acc[val] || 0) + 1;
return acc;
}, {all: combinedMessages.length});
- this.$.reporting.reportInteraction('messages-count', tagsCounted);
+ this.reporting.reportInteraction('messages-count', tagsCounted);
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_html.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_html.js
index 540418b..83edab3 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_html.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_html.js
@@ -45,29 +45,53 @@
align-items: center;
display: flex;
}
+ .hiddenEntries {
+ color: var(--deemphasized-text-color);
+ }
gr-message:not(:last-of-type) {
border-bottom: 1px solid var(--border-color);
}
- gr-message:nth-child(2n) {
+ gr-message {
background-color: var(--background-color-secondary);
}
- gr-message:nth-child(2n + 1) {
- background-color: var(--background-color-tertiary);
+ .experimentMessage {
+ padding: var(--spacing-s) var(--spacing-m);
+ background-color: var(--emphasis-color);
+ border-radius: var(--border-radius);
+ }
+ .experimentMessage iron-icon {
+ vertical-align: top;
}
</style>
<div class="header">
- <span
- id="automatedMessageToggleContainer"
- class="container"
- hidden$="[[!_hasAutomatedMessages(messages)]]"
- >
- <paper-toggle-button
- id="automatedMessageToggle"
- checked="{{_hideAutomated}}"
- ></paper-toggle-button
- >Only comments
- <span class="transparent separator"></span>
- </span>
+ <div id="showAllActivityToggleContainer" class="container">
+ <template
+ is="dom-if"
+ if="[[_isVisibleShowAllActivityToggle(_combinedMessages)]]"
+ >
+ <paper-toggle-button
+ class="showAllActivityToggle"
+ checked="{{_showAllActivity}}"
+ ></paper-toggle-button>
+ <div>
+ <span>Show all entries</span>
+ <span class="hiddenEntries" hidden$="[[_showAllActivity]]">
+ ([[_computeHiddenEntriesCount(_combinedMessages)]] hidden)
+ </span>
+ </div>
+ <span class="transparent separator"></span>
+ </template>
+ </div>
+ <div class="experimentMessage">
+ <iron-icon icon="gr-icons:pets"></iron-icon>
+ <span>You're currently viewing an experimental Change Log view.</span>
+ <a
+ target="_blank"
+ href="https://www.gerritcodereview.com/2020-05-06-change-log-experiment.html"
+ >
+ Learn more
+ </a>
+ </div>
<gr-button
id="collapse-messages"
link=""
@@ -87,7 +111,7 @@
<gr-message
change-num="[[changeNum]]"
message="[[message]]"
- comments="[[_computeCommentsForMessage(changeComments, message)]]"
+ comment-threads="[[message.commentThreads]]"
project-name="[[projectName]]"
show-reply-button="[[showReplyButtons]]"
on-message-anchor-tap="_handleAnchorClick"
@@ -95,5 +119,4 @@
data-message-id$="[[message.id]]"
></gr-message>
</template>
- <gr-reporting id="reporting" category="message-list"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_test.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_test.html
index 9c22ab5..71f25b7 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_test.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list-experimental_test.html
@@ -46,8 +46,11 @@
import '../../../test/common-test-setup.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
import './gr-messages-list-experimental.js';
-import '../../diff/gr-comment-api/gr-comment-api-mock_test.js';
+import '../../../test/mocks/comment-api.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+import {TEST_ONLY} from './gr-messages-list-experimental.js';
+import {MessageTag} from '../../../constants/constants.js';
+
const randomMessage = function(opt_params) {
const params = opt_params || {};
const author1 = {
@@ -61,14 +64,10 @@
message: params.message || Math.random().toString(),
_revision_number: params._revision_number || 1,
author: params.author || author1,
+ tag: params.tag,
};
};
-const randomAutomated = function(opt_params) {
- return Object.assign({tag: 'autogenerated:gerrit:replace'},
- randomMessage(opt_params));
-};
-
suite('gr-messages-list-experimental tests', () => {
let element;
let messages;
@@ -89,61 +88,53 @@
email: 'marvin@sirius.org',
};
+ const createComment = function() {
+ return {
+ id: '1a2b3c4d',
+ message: 'some random test text',
+ change_message_id: '8a7b6c5d',
+ updated: '2016-01-01 01:02:03.000000000',
+ line: 1,
+ patch_set: 1,
+ author,
+ };
+ };
+
const comments = {
file1: [
{
- message: 'message text',
+ ...createComment(),
change_message_id: MESSAGE_ID_0,
- updated: '2016-09-27 00:18:03.000000000',
in_reply_to: '6505d749_f0bec0aa',
- line: 62,
- id: '6505d749_10ed44b2',
- patch_set: 2,
author: {
email: 'some@email.com',
_account_id: 123,
},
},
{
- message: 'message text',
+ ...createComment(),
+ id: '2b3c4d5e',
change_message_id: MESSAGE_ID_1,
- updated: '2016-09-27 00:18:03.000000000',
in_reply_to: 'c5912363_6b820105',
- line: 42,
- id: '450a935e_0f1c05db',
- patch_set: 2,
- author,
},
{
- message: 'message text',
+ ...createComment(),
+ id: '2b3c4d5e',
change_message_id: MESSAGE_ID_1,
- updated: '2016-09-27 00:18:03.000000000',
in_reply_to: '6505d749_f0bec0aa',
- line: 62,
- id: '6505d749_10ed44b2',
- patch_set: 2,
- author,
},
{
- message: 'message text',
- change_message_id: MESSAGE_ID_2,
- updated: '2016-09-27 00:18:03.000000000',
- line: 64,
+ ...createComment(),
id: '34ed05d749_10ed44b2',
- patch_set: 2,
- author,
+ change_message_id: MESSAGE_ID_2,
},
],
file2: [
{
- message: 'message text',
+ ...createComment(),
change_message_id: MESSAGE_ID_1,
- updated: '2016-09-27 00:18:03.000000000',
in_reply_to: 'c5912363_4b7d450a',
- line: 132,
id: '450a935e_4f260d25',
- patch_set: 2,
- author,
},
],
};
@@ -215,9 +206,11 @@
assert.isTrue([...getMessages()].filter(m => m._expanded).length == 0);
});
- test('hide messages does not appear when no automated messages', () => {
+ test('showAllActivity does not appear when all msgs are important', () => {
assert.isOk(element.shadowRoot
- .querySelector('#automatedMessageToggleContainer[hidden]'));
+ .querySelector('#showAllActivityToggleContainer'));
+ assert.isNotOk(element.shadowRoot
+ .querySelector('.showAllActivityToggle'));
});
test('scroll to message', () => {
@@ -265,7 +258,7 @@
._expanded);
});
- test('messages', () => {
+ test('associating messages with comments', () => {
const messages = [].concat(
randomMessage(),
{
@@ -286,25 +279,145 @@
}
);
element.messages = messages;
- const isAuthor = function(author, comment) {
- return comment.author._account_id === author._account_id;
- };
- const isMarvin = isAuthor.bind(null, author);
flushAsynchronousOperations();
const messageElements = getMessages();
assert.equal(messageElements.length, messages.length);
assert.deepEqual(messageElements[1].message, messages[1]);
assert.deepEqual(messageElements[2].message, messages[2]);
- assert.deepEqual(messageElements[1].comments.file1,
- comments.file1.filter(isMarvin).filter(
- c => c.change_message_id === messages[1].id));
- assert.deepEqual(messageElements[1].comments.file2,
- comments.file2.filter(isMarvin).filter(
- c => c.change_message_id === messages[1].id));
- assert.deepEqual(messageElements[2].comments.file1,
- comments.file1.filter(isMarvin).filter(
- c => c.change_message_id === messages[2].id));
- assert.isUndefined(messageElements[2].comments.file2);
+ });
+
+ test('threads', () => {
+ const messages = [
+ {
+ _index: 5,
+ _revision_number: 4,
+ message: 'Uploaded patch set 4.',
+ date: '2016-09-28 13:36:33.000000000',
+ author,
+ id: '8c19ccc949c6d482b061be6a28e10782abf0e7af',
+ },
+ ];
+ element.messages = messages;
+ flushAsynchronousOperations();
+ const messageElements = getMessages();
+ // threads
+ assert.equal(
+ messageElements[0].commentThreads.length,
+ 3);
+ // first thread contains 1 comment
+ assert.equal(
+ messageElements[0].commentThreads[0].comments.length,
+ 1);
+ });
+
+ test('updateTag human message', () => {
+ const m = randomMessage();
+ assert.equal(TEST_ONLY.computeTag(m), undefined);
+ });
+
+ test('updateTag nothing to change', () => {
+ const m = randomMessage();
+ const tag = 'something-normal';
+ m.tag = tag;
+ assert.equal(TEST_ONLY.computeTag(m), tag);
+ });
+
+ test('updateTag TAG_NEW_WIP_PATCHSET', () => {
+ const m = randomMessage();
+ m.tag = MessageTag.TAG_NEW_WIP_PATCHSET;
+ assert.equal(TEST_ONLY.computeTag(m), MessageTag.TAG_NEW_PATCHSET);
+ });
+
+ test('updateTag remove postfix', () => {
+ const m = randomMessage();
+ m.tag = 'something~withpostfix';
+ assert.equal(TEST_ONLY.computeTag(m), 'something');
+ });
+
+ test('updateTag with robot comments', () => {
+ const m = randomMessage();
+ m.commentThreads = [{
+ comments: [{
+ robot_id: 'id314',
+ change_message_id: m.id,
+ }],
+ }];
+ assert.notEqual(TEST_ONLY.computeTag(m), undefined);
+ });
+
+ test('setRevisionNumber nothing to change', () => {
+ const m1 = randomMessage();
+ const m2 = randomMessage();
+ assert.equal(TEST_ONLY.computeRevision(m1, [m1, m2]), 1);
+ assert.equal(TEST_ONLY.computeRevision(m2, [m1, m2]), 1);
+ });
+
+ test('setRevisionNumber reviewer updates', () => {
+ const m1 = randomMessage(
+ {
+ tag: MessageTag.TAG_REVIEWER_UPDATE,
+ date: '2020-01-01 10:00:00.000000000',
+ });
+ m1._revision_number = undefined;
+ const m2 = randomMessage(
+ {
+ date: '2020-01-02 10:00:00.000000000',
+ });
+ m2._revision_number = 1;
+ const m3 = randomMessage(
+ {
+ tag: MessageTag.TAG_REVIEWER_UPDATE,
+ date: '2020-01-03 10:00:00.000000000',
+ });
+ m3._revision_number = undefined;
+ const m4 = randomMessage(
+ {
+ date: '2020-01-04 10:00:00.000000000',
+ });
+ m4._revision_number = 2;
+ const m5 = randomMessage(
+ {
+ tag: MessageTag.TAG_REVIEWER_UPDATE,
+ date: '2020-01-05 10:00:00.000000000',
+ });
+ m5._revision_number = undefined;
+ const allMessages = [m1, m2, m3, m4, m5];
+ assert.equal(TEST_ONLY.computeRevision(m1, allMessages), undefined);
+ assert.equal(TEST_ONLY.computeRevision(m2, allMessages), 1);
+ assert.equal(TEST_ONLY.computeRevision(m3, allMessages), 1);
+ assert.equal(TEST_ONLY.computeRevision(m4, allMessages), 2);
+ assert.equal(TEST_ONLY.computeRevision(m5, allMessages), 2);
+ });
+
+ test('isImportant human message', () => {
+ const m = randomMessage();
+ assert.isTrue(TEST_ONLY.computeIsImportant(m, []));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m, [m]));
+ });
+
+ test('isImportant even with a tag', () => {
+ const m1 = randomMessage();
+ const m2 = randomMessage({tag: 'autogenerated:gerrit1'});
+ const m3 = randomMessage({tag: 'autogenerated:gerrit2'});
+ assert.isTrue(TEST_ONLY.computeIsImportant(m2, []));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m1, [m1, m2, m3]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m2, [m1, m2, m3]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m3, [m1, m2, m3]));
+ });
+
+ test('isImportant filters same tag and older revision', () => {
+ const m1 = randomMessage({tag: 'auto', _revision_number: 2});
+ const m2 = randomMessage({tag: 'auto', _revision_number: 1});
+ const m3 = randomMessage({tag: 'auto'});
+ assert.isTrue(TEST_ONLY.computeIsImportant(m1, [m1]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m2, [m2]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m1, [m1, m2]));
+ assert.isFalse(TEST_ONLY.computeIsImportant(m2, [m1, m2]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m1, [m1, m3]));
+ assert.isFalse(TEST_ONLY.computeIsImportant(m3, [m1, m3]));
+ assert.isTrue(TEST_ONLY.computeIsImportant(m1, [m1, m2, m3]));
+ assert.isFalse(TEST_ONLY.computeIsImportant(m2, [m1, m2, m3]));
+ assert.isFalse(TEST_ONLY.computeIsImportant(m3, [m1, m2, m3]));
});
test('messages without author do not throw', () => {
@@ -329,18 +442,6 @@
let sandbox;
let commentApiWrapper;
- const getMessages = function() {
- return dom(element.root).querySelectorAll('gr-message');
- };
- const getHiddenMessages = function() {
- return dom(element.root).querySelectorAll('gr-message[hidden]');
- };
-
- const randomMessageReviewer = {
- reviewer: {},
- date: '2016-01-13 20:30:33.038000',
- };
-
setup(() => {
stub('gr-rest-api-interface', {
getConfig() { return Promise.resolve({}); },
@@ -351,8 +452,11 @@
});
sandbox = sinon.sandbox.create();
- messages = _.times(2, randomAutomated);
- messages.push(randomMessageReviewer);
+ messages = [
+ randomMessage(),
+ randomMessage({tag: 'auto', _revision_number: 2}),
+ randomMessage({tag: 'auto', _revision_number: 3}),
+ ];
// Element must be wrapped in an element with direct access to the
// comment API.
@@ -371,41 +475,34 @@
});
test('hide autogenerated button is not hidden', () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('#automatedMessageToggle[hidden]'));
+ const toggle = dom(element.root).querySelector('.showAllActivityToggle');
+ assert.isOk(toggle);
});
- test('autogenerated messages are not hidden initially', () => {
- const allHiddenMessageEls = getHiddenMessages();
-
- // There are no hidden messages.
- assert.isFalse(!!allHiddenMessageEls.length);
+ test('one unimportant message is hidden initially', () => {
+ const displayedMsgs = dom(element.root).querySelectorAll('gr-message');
+ assert.equal(displayedMsgs.length, 2);
});
- test('autogenerated messages hidden after comments only toggle', () => {
- let allHiddenMessageEls = getHiddenMessages();
-
- element._hideAutomated = false;
- MockInteractions.tap(element.$.automatedMessageToggle);
+ test('unimportant messages hidden after toggle', () => {
+ element._showAllActivity = true;
+ const toggle = dom(element.root).querySelector('.showAllActivityToggle');
+ assert.isOk(toggle);
+ MockInteractions.tap(toggle);
flushAsynchronousOperations();
- const allMessageEls = getMessages();
- allHiddenMessageEls = getHiddenMessages();
-
- // Autogenerated messages are now hidden.
- assert.equal(allHiddenMessageEls.length, allMessageEls.length);
+ const displayedMsgs = dom(element.root).querySelectorAll('gr-message');
+ assert.equal(displayedMsgs.length, 2);
});
- test('autogenerated messages not hidden after comments only toggle',
- () => {
- let allHiddenMessageEls = getHiddenMessages();
-
- element._hideAutomated = true;
- MockInteractions.tap(element.$.automatedMessageToggle);
- allHiddenMessageEls = getHiddenMessages();
-
- // Autogenerated messages are now hidden.
- assert.isFalse(!!allHiddenMessageEls.length);
- });
+ test('unimportant messages shown after toggle', () => {
+ element._showAllActivity = false;
+ const toggle = dom(element.root).querySelector('.showAllActivityToggle');
+ assert.isOk(toggle);
+ MockInteractions.tap(toggle);
+ flushAsynchronousOperations();
+ const displayedMsgs = dom(element.root).querySelectorAll('gr-message');
+ assert.equal(displayedMsgs.length, 3);
+ });
test('_computeLabelExtremes', () => {
const computeSpy = sandbox.spy(element, '_computeLabelExtremes');
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
index 8df8566..adf9fd3 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-toggle-button/paper-toggle-button.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-button/gr-button.js';
import '../gr-message/gr-message.js';
import '../../../styles/shared-styles.js';
@@ -28,7 +25,8 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-messages-list_html.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
+import {appContext} from '../../../services/app-context.js';
const MAX_INITIAL_SHOWN_MESSAGES = 20;
const MESSAGES_INCREMENT = 5;
@@ -49,7 +47,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrMessagesList extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -122,6 +120,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
scrollToMessage(messageID) {
let el = this.shadowRoot
.querySelector('[data-message-id="' + messageID + '"]');
@@ -188,8 +191,8 @@
result = result.concat(messages.slice(mi));
break;
}
- mDate = mDate || util.parseDate(messages[mi].date);
- rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
+ mDate = mDate || parseDate(messages[mi].date);
+ rDate = rDate || parseDate(reviewerUpdates[ri].date);
if (rDate < mDate) {
result.push(reviewerUpdates[ri++]);
rDate = null;
@@ -238,8 +241,8 @@
_highlightEl(el) {
const highlightedEls =
dom(this.root).querySelectorAll('.highlighted');
- for (const highlighedEl of highlightedEls) {
- highlighedEl.classList.remove('highlighted');
+ for (const highlightedEl of highlightedEls) {
+ highlightedEl.classList.remove('highlighted');
}
function handleAnimationEnd() {
el.removeEventListener('animationend', handleAnimationEnd);
@@ -300,14 +303,14 @@
const messages = this.messages || [];
const index = message._index;
const authorId = message.author && message.author._account_id;
- const mDate = util.parseDate(message.date).getTime();
+ const mDate = parseDate(message.date).getTime();
// NB: Messages array has oldest messages first.
let nextMDate;
if (index > 0) {
for (let i = index - 1; i >= 0; i--) {
if (messages[i] && messages[i].author &&
messages[i].author._account_id === authorId) {
- nextMDate = util.parseDate(messages[i].date).getTime();
+ nextMDate = parseDate(messages[i].date).getTime();
break;
}
}
@@ -321,7 +324,7 @@
fileComments[i].author._account_id !== authorId) {
continue;
}
- const cDate = util.parseDate(fileComments[i].updated).getTime();
+ const cDate = parseDate(fileComments[i].updated).getTime();
if (cDate <= mDate) {
if (nextMDate && cDate <= nextMDate) {
continue;
@@ -401,7 +404,7 @@
_handleShowAllTap() {
this._visibleMessages = this._processedMessages;
- this.$.reporting.reportInteraction(ReportingEvent.SHOW_ALL);
+ this.reporting.reportInteraction(ReportingEvent.SHOW_ALL);
}
_handleIncrementShownMessages() {
@@ -411,7 +414,7 @@
const newMessages = this._processedMessages.slice(-(len + delta), -len);
// Add newMessages to the beginning of _visibleMessages
this.splice(...['_visibleMessages', 0, 0].concat(newMessages));
- this.$.reporting.reportInteraction(ReportingEvent.SHOW_MORE);
+ this.reporting.reportInteraction(ReportingEvent.SHOW_MORE);
}
_processedMessagesChanged(messages) {
@@ -425,7 +428,7 @@
acc[val] = (acc[val] || 0) + 1;
return acc;
}, {all: messages.length});
- this.$.reporting.reportInteraction('messages-count', tagsCounted);
+ this.reporting.reportInteraction('messages-count', tagsCounted);
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.js
index 94ae1b0..ddae150 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.js
@@ -128,5 +128,4 @@
data-message-id$="[[message.id]]"
></gr-message>
</template>
- <gr-reporting id="reporting" category="message-list"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
index 80896aa..4a0f3f1 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
@@ -46,7 +46,7 @@
import '../../../test/common-test-setup.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
import './gr-messages-list.js';
-import '../../diff/gr-comment-api/gr-comment-api-mock_test.js';
+import '../../../test/mocks/comment-api.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
const randomMessage = function(opt_params) {
const params = opt_params || {};
@@ -400,9 +400,15 @@
assert.deepEqual(messageElements[1].message, messages[1]);
assert.deepEqual(messageElements[2].message, messages[2]);
assert.deepEqual(messageElements[1].comments.file1,
- comments.file1.filter(isMarvin));
+ comments.file1.filter(isMarvin).map(c => {
+ return {...c,
+ path: 'file1'};
+ }));
assert.deepEqual(messageElements[1].comments.file2,
- comments.file2.filter(isMarvin));
+ comments.file2.filter(isMarvin).map(c => {
+ return {...c,
+ path: 'file2'};
+ }));
assert.deepEqual(messageElements[2].comments, {});
});
@@ -550,7 +556,7 @@
});
test('initially show only 20 messages', () => {
- sandbox.stub(element.$.reporting, 'reportInteraction',
+ sandbox.stub(element.reporting, 'reportInteraction',
(eventName, details) => {
assert.equal(typeof(eventName), 'string');
if (details) {
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 631542a..8d72d21 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
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../../../styles/shared-styles.js';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -27,9 +25,10 @@
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {ChangeStatus} from '../../../constants/constants.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRelatedChangesList extends mixinBehaviors( [
PatchSetBehavior,
@@ -276,7 +275,7 @@
_computeLinkClass(change) {
const statuses = [];
- if (change.status == this.ChangeStatus.ABANDONED) {
+ if (change.status == ChangeStatus.ABANDONED) {
statuses.push('strikethrough');
}
if (change.submittable) {
@@ -293,7 +292,7 @@
classes.push('indirectAncestor');
} else if (change.submittable) {
classes.push('submittable');
- } else if (change.status == this.ChangeStatus.NEW) {
+ } else if (change.status == ChangeStatus.NEW) {
classes.push('hidden');
}
return classes.join(' ');
@@ -301,9 +300,9 @@
_computeChangeStatus(change) {
switch (change.status) {
- case this.ChangeStatus.MERGED:
+ case ChangeStatus.MERGED:
return 'Merged';
- case this.ChangeStatus.ABANDONED:
+ case ChangeStatus.ABANDONED:
return 'Abandoned';
}
if (change._revision_number != change._current_revision_number) {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index 419e95b..fe3bc67 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
import '../../shared/gr-account-chip/gr-account-chip.js';
import '../../shared/gr-textarea/gr-textarea.js';
@@ -43,6 +40,9 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../../../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {appContext} from '../../../services/app-context.js';
+import {SpecialFilePath} from '../../../constants/constants.js';
+import {ExperimentIds} from '../../../services/flags.js';
const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
@@ -80,7 +80,7 @@
const SEND_REPLY_TIMING_LABEL = 'SendReply';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrReplyDialog extends mixinBehaviors( [
BaseUrlBehavior,
@@ -134,6 +134,8 @@
constructor() {
super();
this.FocusTarget = FocusTarget;
+ this.reporting = appContext.reportingService;
+ this.flagsService = appContext.flagsService;
}
static get properties() {
@@ -259,6 +261,12 @@
type: Array,
observer: '_handleHeightChanged',
},
+ // Track if the message typed in the reply dialog will be created as a
+ // resolved/unresolved patchset level comment
+ _isResolvedPatchsetLevelComment: {
+ type: Boolean,
+ value: true,
+ },
};
}
@@ -292,6 +300,8 @@
/** @override */
ready() {
super.ready();
+ this._isPatchsetCommentsExperimentEnabled = this.flagsService
+ .isEnabled(ExperimentIds.PATCHSET_COMMENTS);
this.$.jsAPI.addElement(this.$.jsAPI.Element.REPLY_DIALOG, this);
}
@@ -477,7 +487,7 @@
}
send(includeComments, startReview) {
- this.$.reporting.time(SEND_REPLY_TIMING_LABEL);
+ this.reporting.time(SEND_REPLY_TIMING_LABEL);
const labels = this.$.labelScores.getLabelValues();
const obj = {
@@ -490,7 +500,17 @@
}
if (this.draft != null) {
- obj.message = this.draft;
+ if (this._isPatchsetCommentsExperimentEnabled) {
+ const comment = {
+ message: this.draft,
+ unresolved: !this._isResolvedPatchsetLevelComment,
+ };
+ obj.comments = {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: [comment],
+ };
+ } else {
+ obj.message = this.draft;
+ }
}
const accountAdditions = {};
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.js
index 54fd47a..7286678 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.js
@@ -137,6 +137,9 @@
#pluginMessage:empty {
display: none;
}
+ .preview-formatting {
+ margin-left: var(--spacing-m);
+ }
</style>
<div class="container" tabindex="-1">
<section class="peopleContainer">
@@ -210,7 +213,17 @@
</gr-endpoint-decorator>
</section>
<section class="previewContainer">
- <label>
+ <template is="dom-if" if="[[_isPatchsetCommentsExperimentEnabled]]">
+ <label>
+ <input
+ id="resolvedPatchsetLevelCommentCheckbox"
+ type="checkbox"
+ checked="{{_isResolvedPatchsetLevelComment::change}}"
+ />
+ Resolved
+ </label>
+ </template>
+ <label class="preview-formatting">
<input type="checkbox" checked="{{_previewFormatting::change}}" />
Preview formatting
</label>
@@ -318,5 +331,4 @@
<gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-storage id="storage"></gr-storage>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index 5a61864..576ee3e 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -36,6 +36,9 @@
import '../../../test/common-test-setup.js';
import './gr-reply-dialog.js';
import {mockPromise} from '../../../test/test-utils.js';
+import {SpecialFilePath} from '../../../constants/constants.js';
+import {appContext} from '../../../services/app-context.js';
+
function cloneableResponse(status, text) {
return {
ok: false,
@@ -82,6 +85,8 @@
getChangeSuggestedReviewers() { return Promise.resolve([]); },
});
+ sandbox.stub(appContext.flagsService, 'isEnabled').returns(true);
+
element = fixture('basic');
element.change = {
_number: changeNum,
@@ -172,7 +177,12 @@
'Code-Review': 0,
'Verified': 0,
},
- message: 'I wholeheartedly disapprove',
+ comments: {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: [{
+ message: 'I wholeheartedly disapprove',
+ unresolved: false,
+ }],
+ },
reviewers: [],
});
assert.isFalse(element.$.commentList.hidden);
@@ -189,6 +199,45 @@
});
});
+ test('toggle resolved checkbox', done => {
+ // Async tick is needed because iron-selector content is distributed and
+ // distributed content requires an observer to be set up.
+ // Note: Double flush seems to be needed in Safari. {@see Issue 4963}.
+ const checkboxEl = element.shadowRoot.querySelector(
+ '#resolvedPatchsetLevelCommentCheckbox');
+ MockInteractions.tap(checkboxEl);
+ flush(() => {
+ flush(() => {
+ element.draft = 'I wholeheartedly disapprove';
+
+ stubSaveReview(review => {
+ assert.deepEqual(review, {
+ drafts: 'PUBLISH_ALL_REVISIONS',
+ labels: {
+ 'Code-Review': 0,
+ 'Verified': 0,
+ },
+ comments: {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: [{
+ message: 'I wholeheartedly disapprove',
+ unresolved: true,
+ }],
+ },
+ reviewers: [],
+ });
+ done();
+ });
+
+ // This is needed on non-Blink engines most likely due to the ways in
+ // which the dom-repeat elements are stamped.
+ flush(() => {
+ MockInteractions.tap(element.shadowRoot
+ .querySelector('.send'));
+ });
+ });
+ });
+ });
+
test('keep draft comments with reply', done => {
MockInteractions.tap(element.shadowRoot.querySelector('#includeComments'));
assert.equal(element._includeComments, false);
@@ -207,7 +256,12 @@
'Code-Review': 0,
'Verified': 0,
},
- message: 'I wholeheartedly disapprove',
+ comments: {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: [{
+ message: 'I wholeheartedly disapprove',
+ unresolved: false,
+ }],
+ },
reviewers: [],
});
assert.isTrue(element.$.commentList.hidden);
@@ -233,7 +287,12 @@
'Code-Review': -1,
'Verified': -1,
},
- message: 'I wholeheartedly disapprove',
+ comments: {
+ [SpecialFilePath.PATCHSET_LEVEL_COMMENTS]: [{
+ message: 'I wholeheartedly disapprove',
+ unresolved: false,
+ }],
+ },
reviewers: [],
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
index c933c7c..88e3160 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-account-chip/gr-account-chip.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -27,7 +25,7 @@
import {htmlTemplate} from './gr-reviewer-list_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrReviewerList extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
index b8079eff..f2455a2 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-comment-thread/gr-comment-thread.js';
@@ -24,7 +22,7 @@
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-thread-list_html.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
import {NO_THREADS_MSG} from '../../../constants/messages.js';
@@ -32,7 +30,7 @@
* Fired when a comment is saved or deleted
*
* @event thread-list-modified
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrThreadList extends GestureEventListeners(
LegacyElementMixin(
@@ -51,12 +49,6 @@
_sortedThreads: {
type: Array,
},
- _filteredThreads: {
- type: Array,
- computed: '_computeFilteredThreads(_sortedThreads, ' +
- '_unresolvedOnly, _draftsOnly,' +
- 'onlyShowRobotCommentsWithHumanReply)',
- },
_unresolvedOnly: {
type: Boolean,
value: false,
@@ -98,108 +90,145 @@
* @param {!Object} changeRecord
*/
_computeSortedThreads(changeRecord) {
- const threads = changeRecord.base;
- if (!threads) { return []; }
- this._updateSortedThreads(threads);
+ const baseThreads = changeRecord.base;
+ const threads = changeRecord.value;
+ if (!baseThreads) { return []; }
+ // TODO: should change how data flows to solve the root cause
+ // We only want to sort on thread additions / removals to avoid
+ // re-rendering on modifications (add new reply / edit draft etc)
+ // https://polymer-library.polymer-project.org/3.0/docs/devguide/observers#array-observation
+ let shouldSort = true;
+ if (threads.indexSplices) {
+ // Array splice mutations
+ shouldSort = threads.indexSplices.addedCount !== 0
+ || threads.indexSplices.removed.length;
+ } else {
+ // A replace mutation
+ shouldSort = threads.length !== baseThreads.length;
+ }
+ this._updateSortedThreads(baseThreads, shouldSort);
}
- // TODO(taoalpha): should allow only sort once during initialization
- // to avoid flickering
- _updateSortedThreads(threads) {
- this._sortedThreads =
- threads.map(this._getThreadWithSortInfo).sort((c1, c2) => {
- // threads will be sorted by:
- // - unresolved first
- // - with drafts
- // - file path
- // - line
- // - updated time
- if (c2.unresolved || c1.unresolved) {
- if (!c1.unresolved) { return 1; }
- if (!c2.unresolved) { return -1; }
- }
-
- if (c2.hasDraft || c1.hasDraft) {
- if (!c1.hasDraft) { return 1; }
- if (!c2.hasDraft) { return -1; }
- }
-
- // TODO: Update here once we introduce patchset level comments
- // they may not have or have a special line or path attribute
-
- if (c1.thread.path !== c2.thread.path) {
- return c1.thread.path.localeCompare(c2.thread.path);
- }
-
- // File level comments (no `line` property)
- // should always show before any lines
- if ([c1, c2].some(c => c.thread.line === undefined)) {
- if (!c1.thread.line) { return -1; }
- if (!c2.thread.line) { return 1; }
- } else if (c1.thread.line !== c2.thread.line) {
- return c1.thread.line - c2.thread.line;
- }
-
- const c1Date = c1.__date || util.parseDate(c1.updated);
- const c2Date = c2.__date || util.parseDate(c2.updated);
- const dateCompare = c2Date - c1Date;
- if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) {
- return 0;
- }
- return dateCompare ? dateCompare : c1.id.localeCompare(c2.id);
- });
- }
-
- _computeFilteredThreads(sortedThreads, unresolvedOnly, draftsOnly,
- onlyShowRobotCommentsWithHumanReply) {
- // Polymer 2: check for undefined
- if ([
- sortedThreads,
- unresolvedOnly,
- draftsOnly,
- onlyShowRobotCommentsWithHumanReply,
- ].some(arg => arg === undefined)) {
- return undefined;
+ _updateSortedThreads(threads, shouldSort) {
+ if (this._sortedThreads
+ && this._sortedThreads.length === threads.length
+ && !shouldSort) {
+ // Instead of replacing the _sortedThreads which will trigger a re-render,
+ // we override all threads inside of it
+ for (const thread of threads) {
+ const idxInSortedThreads = this._sortedThreads
+ .findIndex(t => t.rootId === thread.rootId);
+ this.set(`_sortedThreads.${idxInSortedThreads}`, {...thread});
+ }
+ return;
}
- return sortedThreads.filter(c => {
- if (draftsOnly) {
- return c.hasDraft;
- } else if (unresolvedOnly) {
- return c.unresolved;
- } else {
- const comments = c && c.thread && c.thread.comments;
- let robotComment = false;
- let humanReplyToRobotComment = false;
- comments.forEach(comment => {
- if (comment.robot_id) {
- robotComment = true;
- } else if (robotComment) {
- // Robot comment exists and human comment exists after it
- humanReplyToRobotComment = true;
- }
- });
- if (robotComment && onlyShowRobotCommentsWithHumanReply) {
- return humanReplyToRobotComment;
- }
- return c;
+ const threadsWithInfo = threads
+ .map(thread => this._getThreadWithStatusInfo(thread));
+ this._sortedThreads = threadsWithInfo.sort((c1, c2) => {
+ // threads will be sorted by:
+ // - unresolved first
+ // - with drafts
+ // - file path
+ // - line
+ // - updated time
+ if (c2.unresolved || c1.unresolved) {
+ if (!c1.unresolved) { return 1; }
+ if (!c2.unresolved) { return -1; }
}
+
+ if (c2.hasDraft || c1.hasDraft) {
+ if (!c1.hasDraft) { return 1; }
+ if (!c2.hasDraft) { return -1; }
+ }
+
+ // TODO: Update here once we introduce patchset level comments
+ // they may not have or have a special line or path attribute
+
+ if (c1.thread.path !== c2.thread.path) {
+ return c1.thread.path.localeCompare(c2.thread.path);
+ }
+
+ // File level comments (no `line` property)
+ // should always show before any lines
+ if ([c1, c2].some(c => c.thread.line === undefined)) {
+ if (!c1.thread.line) { return -1; }
+ if (!c2.thread.line) { return 1; }
+ } else if (c1.thread.line !== c2.thread.line) {
+ return c1.thread.line - c2.thread.line;
+ }
+
+ const c1Date = c1.__date || parseDate(c1.updated);
+ const c2Date = c2.__date || parseDate(c2.updated);
+ const dateCompare = c2Date - c1Date;
+ if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) {
+ return 0;
+ }
+ return dateCompare ? dateCompare : c1.id.localeCompare(c2.id);
}).map(threadInfo => threadInfo.thread);
}
- _getThreadWithSortInfo(thread) {
- const lastComment = thread.comments[thread.comments.length - 1] || {};
+ _shouldShowThread(
+ thread, unresolvedOnly, draftsOnly, onlyShowRobotCommentsWithHumanReply
+ ) {
+ if ([
+ thread,
+ unresolvedOnly,
+ draftsOnly,
+ onlyShowRobotCommentsWithHumanReply,
+ ].includes(undefined)) {
+ return false;
+ }
- const lastNonDraftComment =
- (lastComment.__draft && thread.comments.length > 1) ?
- thread.comments[thread.comments.length - 2] :
- lastComment;
+ if (!draftsOnly
+ && !unresolvedOnly
+ && !onlyShowRobotCommentsWithHumanReply) {
+ return true;
+ }
+
+ const threadInfo = this._getThreadWithStatusInfo(thread);
+
+ if (threadInfo.isEditing) {
+ return true;
+ }
+
+ if (threadInfo.hasRobotComment
+ && onlyShowRobotCommentsWithHumanReply
+ && !threadInfo.hasHumanReplyToRobotComment) {
+ return false;
+ }
+
+ let filtersCheck = true;
+ if (draftsOnly && unresolvedOnly) {
+ filtersCheck = threadInfo.hasDraft && threadInfo.unresolved;
+ } else if (draftsOnly) {
+ filtersCheck = threadInfo.hasDraft;
+ } else if (unresolvedOnly) {
+ filtersCheck = threadInfo.unresolved;
+ }
+
+ return filtersCheck;
+ }
+
+ _getThreadWithStatusInfo(thread) {
+ const comments = thread.comments;
+ const lastComment = comments[comments.length - 1] || {};
+ let hasRobotComment = false;
+ let hasHumanReplyToRobotComment = false;
+ comments.forEach(comment => {
+ if (comment.robot_id) {
+ hasRobotComment = true;
+ } else if (hasRobotComment) {
+ hasHumanReplyToRobotComment = true;
+ }
+ });
return {
thread,
- // Use the unresolved bit for the last non draft comment. This is what
- // anybody other than the current user would see.
- unresolved: !!lastNonDraftComment.unresolved,
+ hasRobotComment,
+ hasHumanReplyToRobotComment,
+ unresolved: !!lastComment.unresolved,
+ isEditing: !!lastComment.__editing,
hasDraft: !!lastComment.__draft,
updated: lastComment.updated || lastComment.__date,
};
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.js b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.js
index fd34b2d..721e7510 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.js
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.js
@@ -80,25 +80,30 @@
</template>
<template
is="dom-repeat"
- items="[[_filteredThreads]]"
+ items="[[_sortedThreads]]"
as="thread"
- initial-count="5"
+ initial-count="10"
target-framerate="60"
>
- <gr-comment-thread
- show-file-path=""
- change-num="[[changeNum]]"
- comments="[[thread.comments]]"
- comment-side="[[thread.commentSide]]"
- project-name="[[change.project]]"
- is-on-parent="[[_isOnParent(thread.commentSide)]]"
- line-num="[[thread.line]]"
- patch-num="[[thread.patchNum]]"
- path="[[thread.path]]"
- root-id="{{thread.rootId}}"
- on-thread-changed="_handleCommentsChanged"
- on-thread-discard="_handleThreadDiscard"
- ></gr-comment-thread>
+ <template
+ is="dom-if"
+ if="[[_shouldShowThread(thread, _unresolvedOnly, _draftsOnly, onlyShowRobotCommentsWithHumanReply)]]"
+ >
+ <gr-comment-thread
+ show-file-path=""
+ change-num="[[changeNum]]"
+ comments="[[thread.comments]]"
+ comment-side="[[thread.commentSide]]"
+ project-name="[[change.project]]"
+ is-on-parent="[[_isOnParent(thread.commentSide)]]"
+ line-num="[[thread.line]]"
+ patch-num="[[thread.patchNum]]"
+ path="[[thread.path]]"
+ root-id="{{thread.rootId}}"
+ on-thread-changed="_handleCommentsChanged"
+ on-thread-discard="_handleThreadDiscard"
+ ></gr-comment-thread>
+ </template>
</template>
</div>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
index 4b00d5a..2195581 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
@@ -41,10 +41,15 @@
let sandbox;
let threadElements;
- setup(() => {
+ function getVisibleThreads() {
+ return [...dom(element.root)
+ .querySelectorAll('gr-comment-thread')]
+ .filter(e => e.style.display !== 'none');
+ }
+
+ setup(done => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
- element.onlyShowRobotCommentsWithHumanReply = true;
element.threads = [
{
comments: [
@@ -69,7 +74,7 @@
in_reply_to: 'ecf0b9fa_fe1a5f62',
updated: '2018-02-13 22:48:48.018000000',
message: 'draft',
- unresolved: false,
+ unresolved: true,
__draft: true,
__draftID: '0.m683trwff68',
__editing: false,
@@ -233,9 +238,13 @@
start_datetime: '2019-03-08 18:49:18.000000000',
},
];
- flushAsynchronousOperations();
- threadElements = dom(element.root)
- .querySelectorAll('gr-comment-thread');
+
+ // use flush to render all (bypass initial-count set on dom-repeat)
+ flush(() => {
+ threadElements = dom(element.root)
+ .querySelectorAll('gr-comment-thread');
+ done();
+ });
});
teardown(() => {
@@ -252,48 +261,47 @@
'none');
});
- test('there are five threads by default', () => {
+ test('show all threads by default', () => {
assert.equal(dom(element.root)
- .querySelectorAll('gr-comment-thread').length, 5);
+ .querySelectorAll('gr-comment-thread').length, element.threads.length);
+ assert.equal(getVisibleThreads().length, element.threads.length);
+ });
+
+ test('onlyShowRobotCommentsWithHumanReply ', () => {
+ element.onlyShowRobotCommentsWithHumanReply = true;
+ flushAsynchronousOperations();
+ assert.equal(
+ getVisibleThreads().length,
+ element.threads.length - 1);
+ assert.isNotOk(getVisibleThreads().find(th => th.rootId === 'rc1'));
});
test('_computeSortedThreads', () => {
assert.equal(element._sortedThreads.length, 7);
// Draft and unresolved for commit-msg at line 5
- assert.equal(element._sortedThreads[0].thread.rootId,
+ assert.equal(element._sortedThreads[0].rootId,
'ecf0b9fa_fe1a5f62');
- // /COMMIT_MSG
// unresolved no draft and file level
- assert.equal(element._sortedThreads[1].thread.rootId,
+ assert.equal(element._sortedThreads[1].rootId,
'8caddf38_44770ec1');
// unresolved no draft at line 4
- assert.equal(element._sortedThreads[2].thread.rootId,
+ assert.equal(element._sortedThreads[2].rootId,
'scaddf38_44770ec1');
// unresolved no draft at line 5
- assert.equal(element._sortedThreads[3].thread.rootId,
+ assert.equal(element._sortedThreads[3].rootId,
'rc1');
// Unresolved no draft at line 7
- assert.equal(element._sortedThreads[4].thread.rootId,
+ assert.equal(element._sortedThreads[4].rootId,
'rc2');
// resolved and draft on COMMIT_MSG
- assert.equal(element._sortedThreads[5].thread.rootId,
+ assert.equal(element._sortedThreads[5].rootId,
'zcf0b9fa_fe1a5f62');
// resolved and on file test.txt
- assert.equal(element._sortedThreads[6].thread.rootId,
+ assert.equal(element._sortedThreads[6].rootId,
'09a9fb0a_1484e6cf');
});
- test('filtered threads do not contain robot comments without reply', () => {
- const thread = element.threads.find(thread => thread.rootId === 'rc1');
- assert.equal(element._filteredThreads.includes(thread), false);
- });
-
- test('filtered threads contains robot comments with reply', () => {
- const thread = element.threads.find(thread => thread.rootId === 'rc2');
- assert.equal(element._filteredThreads.includes(thread), true);
- });
-
- test('thread removal', () => {
+ test('thread removal and sort again', () => {
threadElements[1].dispatchEvent(
new CustomEvent('thread-discard', {
detail: {rootId: 'rc2'},
@@ -301,23 +309,95 @@
}));
flushAsynchronousOperations();
assert.equal(element._sortedThreads.length, 6);
- assert.equal(element._sortedThreads[0].thread.rootId,
+ assert.equal(element._sortedThreads[0].rootId,
+ 'ecf0b9fa_fe1a5f62');
+ // unresolved no draft and file level
+ assert.equal(element._sortedThreads[1].rootId,
+ '8caddf38_44770ec1');
+ // unresolved no draft at line 4
+ assert.equal(element._sortedThreads[2].rootId,
+ 'scaddf38_44770ec1');
+ // unresolved no draft at line 5
+ assert.equal(element._sortedThreads[3].rootId,
+ 'rc1');
+ // resolved and draft
+ assert.equal(element._sortedThreads[4].rootId,
+ 'zcf0b9fa_fe1a5f62');
+ // resolved and on file test.txt
+ assert.equal(element._sortedThreads[5].rootId,
+ '09a9fb0a_1484e6cf');
+ });
+
+ test('modification on thread shold not trigger sort again', () => {
+ const currentSortedThreads = [...element._sortedThreads];
+ for (const thread of currentSortedThreads) {
+ thread.comments = [...thread.comments];
+ }
+ const modifiedThreads = [...element.threads];
+ modifiedThreads[5] = {...modifiedThreads[5]};
+ modifiedThreads[5].comments = [...modifiedThreads[5].comments, {
+ ...modifiedThreads[5].comments[0],
+ unresolved: false,
+ }];
+ element.threads = modifiedThreads;
+ assert.notDeepEqual(currentSortedThreads, element._sortedThreads);
+
+ // exact same order as in _computeSortedThreads
+ assert.equal(element._sortedThreads.length, 7);
+ // Draft and unresolved for commit-msg at line 5
+ assert.equal(element._sortedThreads[0].rootId,
+ 'ecf0b9fa_fe1a5f62');
+ // unresolved no draft and file level
+ assert.equal(element._sortedThreads[1].rootId,
+ '8caddf38_44770ec1');
+ // unresolved no draft at line 4
+ assert.equal(element._sortedThreads[2].rootId,
+ 'scaddf38_44770ec1');
+ // unresolved no draft at line 5
+ assert.equal(element._sortedThreads[3].rootId,
+ 'rc1');
+ // Unresolved no draft at line 7
+ assert.equal(element._sortedThreads[4].rootId,
+ 'rc2');
+ // resolved and draft on COMMIT_MSG
+ assert.equal(element._sortedThreads[5].rootId,
+ 'zcf0b9fa_fe1a5f62');
+ // resolved and on file test.txt
+ assert.equal(element._sortedThreads[6].rootId,
+ '09a9fb0a_1484e6cf');
+ });
+
+ test('non-equal length of sortThreads and threads' +
+ ' shold trigger sort again', () => {
+ const modifiedThreads = [...element.threads];
+ const currentSortedThreads = [...element._sortedThreads];
+ element._sortedThreads = [];
+ element.threads = modifiedThreads;
+ assert.deepEqual(currentSortedThreads, element._sortedThreads);
+
+ // exact same order as in _computeSortedThreads
+ assert.equal(element._sortedThreads.length, 7);
+ // Draft and unresolved for commit-msg at line 5
+ assert.equal(element._sortedThreads[0].rootId,
'ecf0b9fa_fe1a5f62');
// /COMMIT_MSG
// unresolved no draft and file level
- assert.equal(element._sortedThreads[1].thread.rootId,
+ assert.equal(element._sortedThreads[1].rootId,
'8caddf38_44770ec1');
// unresolved no draft at line 4
- assert.equal(element._sortedThreads[2].thread.rootId,
+ assert.equal(element._sortedThreads[2].rootId,
'scaddf38_44770ec1');
// unresolved no draft at line 5
- assert.equal(element._sortedThreads[3].thread.rootId,
+ assert.equal(element._sortedThreads[3].rootId,
'rc1');
- // resolved and draft
- assert.equal(element._sortedThreads[4].thread.rootId,
+ // Unresolved no draft at line 7
+ assert.equal(element._sortedThreads[4].rootId,
+ 'rc2');
+ // resolved and draft on COMMIT_MSG
+ assert.equal(element._sortedThreads[5].rootId,
'zcf0b9fa_fe1a5f62');
// resolved and on file test.txt
- assert.equal(element._sortedThreads[5].thread.rootId,
+ assert.equal(element._sortedThreads[6].rootId,
'09a9fb0a_1484e6cf');
});
@@ -325,15 +405,29 @@
MockInteractions.tap(element.shadowRoot.querySelector(
'#unresolvedToggle'));
flushAsynchronousOperations();
- assert.equal(dom(element.root)
- .querySelectorAll('gr-comment-thread').length, 5);
+ assert.equal(getVisibleThreads().length, 5);
});
test('toggle drafts only shows threads with draft comments', () => {
MockInteractions.tap(element.shadowRoot.querySelector('#draftToggle'));
flushAsynchronousOperations();
- assert.equal(dom(element.root)
- .querySelectorAll('gr-comment-thread').length, 2);
+ assert.equal(getVisibleThreads().length, 2);
+ });
+
+ test('toggle drafts and unresolved should ignore comments in editing', () => {
+ const modifiedThreads = [...element.threads];
+ modifiedThreads[5] = {...modifiedThreads[5]};
+ modifiedThreads[5].comments = [...modifiedThreads[5].comments];
+ modifiedThreads[5].comments.push({
+ ...modifiedThreads[5].comments[0],
+ __editing: true,
+ });
+ element.threads = modifiedThreads;
+ MockInteractions.tap(element.shadowRoot.querySelector('#draftToggle'));
+ MockInteractions.tap(element.shadowRoot.querySelector(
+ '#unresolvedToggle'));
+ flushAsynchronousOperations();
+ assert.equal(getVisibleThreads().length, 2);
});
test('toggle drafts and unresolved only shows threads with drafts and ' +
@@ -342,8 +436,7 @@
MockInteractions.tap(element.shadowRoot.querySelector(
'#unresolvedToggle'));
flushAsynchronousOperations();
- assert.equal(dom(element.root)
- .querySelectorAll('gr-comment-thread').length, 2);
+ assert.equal(getVisibleThreads().length, 1);
});
test('modification events are consumed and displatched', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
index 9171908..0658996 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../../shared/gr-shell-command/gr-shell-command.js';
@@ -36,7 +34,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrUploadHelpDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
index 2645c63..903552a 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-dropdown/gr-dropdown.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -27,10 +26,10 @@
import {htmlTemplate} from './gr-account-dropdown_html.js';
import {DisplayNameBehavior} from '../../../behaviors/gr-display-name-behavior/gr-display-name-behavior.js';
-const INTERPOLATE_URL_PATTERN = /\$\{([\w]+)\}/g;
+const INTERPOLATE_URL_PATTERN = /\${([\w]+)}/g;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountDropdown extends mixinBehaviors( [
DisplayNameBehavior,
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.js b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.js
index 6814d89..99c4cb3 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.js
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-error-dialog_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrErrorDialog extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
index 4b5969a..9f6d050 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
@@ -16,15 +16,7 @@
*/
/* Import to get Gerrit interface */
/* TODO(taoalpha): decouple gr-gerrit from gr-js-api-interface */
-/*
- FIXME(polymer-modulizer): the above comments were extracted
- from HTML and may be out of place here. Review them and
- then delete this comment!
-*/
-
-import '../../../scripts/bundled-polymer.js';
import '../gr-error-dialog/gr-error-dialog.js';
-import '../gr-reporting/gr-reporting.js';
import '../../shared/gr-alert/gr-alert.js';
import '../../shared/gr-overlay/gr-overlay.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -37,6 +29,7 @@
import {BaseUrlBehavior} from '../../../behaviors/base-url-behavior/base-url-behavior.js';
import {authService} from '../../shared/gr-rest-api-interface/gr-auth.js';
import {gerritEventEmitter} from '../../shared/gr-event-emitter/gr-event-emitter.js';
+import {appContext} from '../../../services/app-context.js';
const HIDE_ALERT_TIMEOUT_MS = 5000;
const CHECK_SIGN_IN_INTERVAL_MS = 60 * 1000;
@@ -47,7 +40,7 @@
const AUTHENTICATION_REQUIRED = 'Authentication required\n';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrErrorManager extends mixinBehaviors( [
BaseUrlBehavior,
@@ -98,6 +91,8 @@
/** @type {?Function} */
this._authErrorHandlerDeregistrationHook;
+
+ this.reporting = appContext.reportingService;
}
/** @override */
@@ -205,7 +200,6 @@
showSignInButton: !isLoggedIn,
});
});
- return;
}
_constructServerErrorMsg({errorText, status, statusText, url, trace, tip}) {
@@ -406,7 +400,7 @@
}
_showErrorDialog(message, opt_options) {
- this.$.reporting.reportErrorDialog(message);
+ this.reporting.reportErrorDialog(message);
this.$.errorDialog.text = message;
this.$.errorDialog.showSignInButton =
opt_options && opt_options.showSignInButton;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.js
index 4d32f24..2fa9b95 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.js
@@ -35,5 +35,4 @@
>
</gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
index 8272c6e..b52bb7d 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
@@ -24,11 +24,6 @@
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/components/wct-browser-legacy/browser.js"></script>
-<script type="module">
-import '../../../test/common-test-setup.js';
-import './gr-error-manager.js';
-void (0);
-</script>
<test-fixture id="basic">
<template>
@@ -338,7 +333,7 @@
}));
assert.equal(window.fetch.callCount, 1);
flush(() => {
- // here needs two flush as there are two chanined
+ // here needs two flush as there are two chained
// promises on server-error handler and flush only flushes one
assert.equal(window.fetch.callCount, 2);
flush(() => {
@@ -396,7 +391,7 @@
}));
assert.equal(window.fetch.callCount, 1);
flush(() => {
- // here needs two flush as there are two chanined
+ // here needs two flush as there are two chained
// promises on server-error handler and flush only flushes one
assert.equal(window.fetch.callCount, 2);
flush(() => {
@@ -490,7 +485,7 @@
const openStub = sandbox.stub(element.$.errorOverlay, 'open');
const closeStub = sandbox.stub(element.$.errorOverlay, 'close');
const reportStub = sandbox.stub(
- element.$.reporting,
+ element.reporting,
'reportErrorDialog'
);
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.js b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.js
index 5d7ec27..5c54011 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.js
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-key-binding-display_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrKeyBindingDisplay extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
index beb0f7e..0c0daea 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-button/gr-button.js';
import '../gr-key-binding-display/gr-key-binding-display.js';
import '../../../styles/shared-styles.js';
@@ -29,7 +27,7 @@
const {ShortcutSection} = KeyboardShortcutBinder;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrKeyboardShortcutsDialog extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
index 3294f5f..684b472 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
import '../../shared/gr-dropdown/gr-dropdown.js';
import '../../shared/gr-icons/gr-icons.js';
@@ -86,7 +84,7 @@
]);
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrMainHeader extends mixinBehaviors( [
AdminNavBehavior,
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.js b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.js
index 2b87548..69e2989 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.js
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.js
@@ -86,7 +86,7 @@
const EDIT_PATCHNUM = 'edit';
const PARENT_PATCHNUM = 'PARENT';
-const USER_PLACEHOLDER_PATTERN = /\$\{user\}/g;
+const USER_PLACEHOLDER_PATTERN = /\${user}/g;
// NOTE: These queries are tested in Java. Any changes made to definitions
// here require corresponding changes to:
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
deleted file mode 100644
index e140d6c..0000000
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
+++ /dev/null
@@ -1,437 +0,0 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2016 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">
-<meta charset="utf-8">
-<title>gr-reporting</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-
-<test-fixture id="basic">
- <template>
- <gr-reporting></gr-reporting>
- </template>
-</test-fixture>
-
-<script type="module">
-import '../../../test/common-test-setup.js';
-import './gr-reporting.js';
-suite('gr-reporting tests', () => {
- let element;
- let sandbox;
- let clock;
- let fakePerformance;
-
- const NOW_TIME = 100;
-
- setup(() => {
- sandbox = sinon.sandbox.create();
- clock = sinon.useFakeTimers(NOW_TIME);
- element = fixture('basic');
- element._baselines = Object.assign({}, GrReporting.STARTUP_TIMERS);
- fakePerformance = {
- navigationStart: 1,
- loadEventEnd: 2,
- };
- fakePerformance.toJSON = () => fakePerformance;
- sinon.stub(element, 'performanceTiming',
- {get() { return fakePerformance; }});
- sandbox.stub(element, 'reporter');
- });
-
- teardown(() => {
- sandbox.restore();
- clock.restore();
- });
-
- test('appStarted', () => {
- sandbox.stub(element, 'now').returns(42);
- element.appStarted();
- assert.isTrue(
- element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'App Started', 42
- ));
- assert.isTrue(
- element.reporter.calledWithExactly(
- 'timing-report', 'UI Latency', 'NavResTime - loadEventEnd',
- fakePerformance.loadEventEnd - fakePerformance.navigationStart,
- undefined, true)
- );
- });
-
- test('WebComponentsReady', () => {
- sandbox.stub(element, 'now').returns(42);
- element.timeEnd('WebComponentsReady');
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'WebComponentsReady', 42
- ));
- });
-
- test('beforeLocationChanged', () => {
- element._baselines['garbage'] = 'monster';
- sandbox.stub(element, 'time');
- element.beforeLocationChanged();
- assert.isTrue(element.time.calledWithExactly('DashboardDisplayed'));
- assert.isTrue(element.time.calledWithExactly('ChangeDisplayed'));
- assert.isTrue(element.time.calledWithExactly('ChangeFullyLoaded'));
- assert.isTrue(element.time.calledWithExactly('DiffViewDisplayed'));
- assert.isTrue(element.time.calledWithExactly('FileListDisplayed'));
- assert.isFalse(element._baselines.hasOwnProperty('garbage'));
- });
-
- test('changeDisplayed', () => {
- sandbox.spy(element, 'timeEnd');
- element.changeDisplayed();
- assert.isFalse(element.timeEnd.calledWith('ChangeDisplayed'));
- assert.isTrue(element.timeEnd.calledWith('StartupChangeDisplayed'));
- element.changeDisplayed();
- assert.isTrue(element.timeEnd.calledWith('ChangeDisplayed'));
- });
-
- test('changeFullyLoaded', () => {
- sandbox.spy(element, 'timeEnd');
- element.changeFullyLoaded();
- assert.isFalse(
- element.timeEnd.calledWithExactly('ChangeFullyLoaded'));
- assert.isTrue(
- element.timeEnd.calledWithExactly('StartupChangeFullyLoaded'));
- element.changeFullyLoaded();
- assert.isTrue(element.timeEnd.calledWithExactly('ChangeFullyLoaded'));
- });
-
- test('diffViewDisplayed', () => {
- sandbox.spy(element, 'timeEnd');
- element.diffViewDisplayed();
- assert.isFalse(element.timeEnd.calledWith('DiffViewDisplayed'));
- assert.isTrue(element.timeEnd.calledWith('StartupDiffViewDisplayed'));
- element.diffViewDisplayed();
- assert.isTrue(element.timeEnd.calledWith('DiffViewDisplayed'));
- });
-
- test('fileListDisplayed', () => {
- sandbox.spy(element, 'timeEnd');
- element.fileListDisplayed();
- assert.isFalse(
- element.timeEnd.calledWithExactly('FileListDisplayed'));
- assert.isTrue(
- element.timeEnd.calledWithExactly('StartupFileListDisplayed'));
- element.fileListDisplayed();
- assert.isTrue(element.timeEnd.calledWithExactly('FileListDisplayed'));
- });
-
- test('dashboardDisplayed', () => {
- sandbox.spy(element, 'timeEnd');
- element.dashboardDisplayed();
- assert.isFalse(element.timeEnd.calledWith('DashboardDisplayed'));
- assert.isTrue(element.timeEnd.calledWith('StartupDashboardDisplayed'));
- element.dashboardDisplayed();
- assert.isTrue(element.timeEnd.calledWith('DashboardDisplayed'));
- });
-
- test('dashboardDisplayed details', () => {
- sandbox.spy(element, 'timeEnd');
- sandbox.stub(window, 'performance', {
- memory: {
- usedJSHeapSize: 1024 * 1024,
- },
- measure: () => {},
- });
- sandbox.stub(element, 'now').returns(42);
- element.reportRpcTiming('/changes/*~*/comments', 500);
- element.dashboardDisplayed();
- assert.isTrue(
- element.timeEnd.calledWithExactly('StartupDashboardDisplayed',
- {rpcList: [
- {
- anonymizedUrl: '/changes/*~*/comments',
- elapsed: 500,
- },
- ],
- screenSize: {
- width: window.screen.width,
- height: window.screen.height,
- },
- viewport: {
- width: document.documentElement.clientWidth,
- height: document.documentElement.clientHeight,
- },
- usedJSHeapSizeMb: 1,
- }
- ));
- });
-
- test('time and timeEnd', () => {
- const nowStub = sandbox.stub(element, 'now').returns(0);
- element.time('foo');
- nowStub.returns(1);
- element.time('bar');
- nowStub.returns(2);
- element.timeEnd('bar');
- nowStub.returns(3);
- element.timeEnd('foo');
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'foo', 3
- ));
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'bar', 1
- ));
- });
-
- test('timer object', () => {
- const nowStub = sandbox.stub(element, 'now').returns(100);
- const timer = element.getTimer('foo-bar');
- nowStub.returns(150);
- timer.end();
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'foo-bar', 50));
- });
-
- test('timer object double call', () => {
- const timer = element.getTimer('foo-bar');
- timer.end();
- assert.isTrue(element.reporter.calledOnce);
- assert.throws(() => {
- timer.end();
- }, 'Timer for "foo-bar" already ended.');
- });
-
- test('timer object maximum', () => {
- const nowStub = sandbox.stub(element, 'now').returns(100);
- const timer = element.getTimer('foo-bar').withMaximum(100);
- nowStub.returns(150);
- timer.end();
- assert.isTrue(element.reporter.calledOnce);
-
- timer.reset();
- nowStub.returns(260);
- timer.end();
- assert.isTrue(element.reporter.calledOnce);
- });
-
- test('recordDraftInteraction', () => {
- const key = 'TimeBetweenDraftActions';
- const nowStub = sandbox.stub(element, 'now').returns(100);
- const timingStub = sandbox.stub(element, '_reportTiming');
- element.recordDraftInteraction();
- assert.isFalse(timingStub.called);
-
- nowStub.returns(200);
- element.recordDraftInteraction();
- assert.isTrue(timingStub.calledOnce);
- assert.equal(timingStub.lastCall.args[0], key);
- assert.equal(timingStub.lastCall.args[1], 100);
-
- nowStub.returns(350);
- element.recordDraftInteraction();
- assert.isTrue(timingStub.calledTwice);
- assert.equal(timingStub.lastCall.args[0], key);
- assert.equal(timingStub.lastCall.args[1], 150);
-
- nowStub.returns(370 + 2 * 60 * 1000);
- element.recordDraftInteraction();
- assert.isFalse(timingStub.calledThrice);
- });
-
- test('timeEndWithAverage', () => {
- const nowStub = sandbox.stub(element, 'now').returns(0);
- nowStub.returns(1000);
- element.time('foo');
- nowStub.returns(1100);
- element.timeEndWithAverage('foo', 'bar', 10);
- assert.isTrue(element.reporter.calledTwice);
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'foo', 100));
- assert.isTrue(element.reporter.calledWithMatch(
- 'timing-report', 'UI Latency', 'bar', 10));
- });
-
- test('reportExtension', () => {
- element.reportExtension('foo');
- assert.isTrue(element.reporter.calledWithExactly(
- 'lifecycle', 'Extension detected', 'foo'
- ));
- });
-
- test('reportInteraction', () => {
- element.reporter.restore();
- sandbox.spy(element, '_reportEvent');
- element.pluginsLoaded(); // so we don't cache
- element.reportInteraction('button-click', {name: 'sendReply'});
- assert.isTrue(element._reportEvent.getCall(2).calledWithMatch(
- {
- type: 'interaction',
- name: 'button-click',
- eventDetails: JSON.stringify({name: 'sendReply'}),
- }
- ));
- });
-
- test('report start time', () => {
- element.reporter.restore();
- sandbox.stub(element, 'now').returns(42);
- sandbox.spy(element, '_reportEvent');
- const dispatchStub = sandbox.spy(document, 'dispatchEvent');
- element.pluginsLoaded();
- element.time('timeAction');
- element.timeEnd('timeAction');
- assert.isTrue(element._reportEvent.getCall(2).calledWithMatch(
- {
- type: 'timing-report',
- category: 'UI Latency',
- name: 'timeAction',
- value: 0,
- eventStart: 42,
- }
- ));
- assert.equal(dispatchStub.getCall(2).args[0].detail.eventStart, 42);
- });
-
- suite('plugins', () => {
- setup(() => {
- element.reporter.restore();
- sandbox.stub(element, '_reportEvent');
- });
-
- test('pluginsLoaded reports time', () => {
- sandbox.stub(element, 'now').returns(42);
- element.pluginsLoaded();
- assert.isTrue(element._reportEvent.calledWithMatch(
- {
- type: 'timing-report',
- category: 'UI Latency',
- name: 'PluginsLoaded',
- value: 42,
- }
- ));
- });
-
- test('pluginsLoaded reports plugins', () => {
- element.pluginsLoaded(['foo', 'bar']);
- assert.isTrue(element._reportEvent.calledWithMatch(
- {
- type: 'lifecycle',
- category: 'Plugins installed',
- eventDetails: JSON.stringify({pluginsList: ['foo', 'bar']}),
- }
- ));
- });
-
- test('caches reports if plugins are not loaded', () => {
- element.timeEnd('foo');
- assert.isFalse(element._reportEvent.called);
- });
-
- test('reports if plugins are loaded', () => {
- element.pluginsLoaded();
- assert.isTrue(element._reportEvent.called);
- });
-
- test('reports if metrics plugin xyz is loaded', () => {
- element.pluginLoaded('metrics-xyz');
- assert.isTrue(element._reportEvent.called);
- });
-
- test('reports cached events preserving order', () => {
- element.time('foo');
- element.time('bar');
- element.timeEnd('foo');
- element.pluginsLoaded();
- element.timeEnd('bar');
- assert.isTrue(element._reportEvent.getCall(0).calledWithMatch(
- {type: 'timing-report', category: 'UI Latency', name: 'foo'}
- ));
- assert.isTrue(element._reportEvent.getCall(1).calledWithMatch(
- {type: 'timing-report', category: 'UI Latency',
- name: 'PluginsLoaded'}
- ));
- assert.isTrue(element._reportEvent.getCall(2).calledWithMatch(
- {type: 'lifecycle', category: 'Plugins installed'}
- ));
- assert.isTrue(element._reportEvent.getCall(3).calledWithMatch(
- {type: 'timing-report', category: 'UI Latency', name: 'bar'}
- ));
- });
- });
-
- test('search', () => {
- element.locationChanged('_handleSomeRoute');
- assert.isTrue(element.reporter.calledWithExactly(
- 'nav-report', 'Location Changed', 'Page', '_handleSomeRoute'));
- });
-
- suite('exception logging', () => {
- let fakeWindow;
- let reporter;
-
- const emulateThrow = function(msg, url, line, column, error) {
- return fakeWindow.onerror(msg, url, line, column, error);
- };
-
- setup(() => {
- reporter = sandbox.stub(GrReporting.prototype, 'reporter');
- fakeWindow = {
- handlers: {},
- addEventListener(type, handler) {
- this.handlers[type] = handler;
- },
- };
- sandbox.stub(console, 'error');
- window.GrReporting._catchErrors(fakeWindow);
- });
-
- test('is reported', () => {
- const error = new Error('bar');
- error.stack = undefined;
- emulateThrow('bar', 'http://url', 4, 2, error);
- assert.isTrue(reporter.calledWith('error', 'exception', 'bar'));
- const payload = reporter.lastCall.args[3];
- assert.deepEqual(payload, {
- url: 'http://url',
- line: 4,
- column: 2,
- error,
- });
- });
-
- test('is reported with 3 lines of stack', () => {
- const error = new Error('bar');
- emulateThrow('bar', 'http://url', 4, 2, error);
- const expectedStack = error.stack.split('\n').slice(0, 3)
- .join('\n');
- assert.isTrue(reporter.calledWith('error', 'exception',
- expectedStack));
- });
-
- test('prevent default event handler', () => {
- assert.isTrue(emulateThrow());
- });
-
- test('unhandled rejection', () => {
- fakeWindow.handlers['unhandledrejection']({
- reason: {
- message: 'bar',
- },
- });
- assert.isTrue(reporter.calledWith('error', 'exception', 'bar'));
- });
- });
-});
-</script>
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 11465ba..c1cf169 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
-import '../gr-reporting/gr-reporting.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -28,6 +25,7 @@
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
import {URLEncodingBehavior} from '../../../behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior.js';
import {GerritNav} from '../gr-navigation/gr-navigation.js';
+import {appContext} from '../../../services/app-context.js';
const RoutePattern = {
ROOT: '/',
@@ -145,7 +143,7 @@
DIFF: /^\/c\/(.+)\/\+\/(\d+)(\/((-?\d+|edit)(\.\.(\d+|edit))?(\/(.+))))\/?$/,
// Matches /c/<project>/+/<changeNum>/[<patchNum|edit>]/<path>,edit[#lineNum]
- DIFF_EDIT: /^\/c\/(.+)\/\+\/(\d+)\/(\d+|edit)\/(.+),edit(\#\d+)?$/,
+ DIFF_EDIT: /^\/c\/(.+)\/\+\/(\d+)\/(\d+|edit)\/(.+),edit(#\d+)?$/,
// Matches non-project-relative
// /c/<changeNum>/[<basePatchNum>..]<patchNum>/<path>.
@@ -161,7 +159,7 @@
// Matches /c/<changeNum>/ /<URL tail>
// Catches improperly encoded URLs (context: Issue 7100)
- IMPROPERLY_ENCODED_PLUS: /^\/c\/(.+)\/\ \/(.+)$/,
+ IMPROPERLY_ENCODED_PLUS: /^\/c\/(.+)\/ \/(.+)$/,
PLUGIN_SCREEN: /^\/x\/([\w-]+)\/([\w-]+)\/?/,
@@ -197,7 +195,7 @@
const LEGACY_QUERY_SUFFIX_PATTERN = /,n,z$/;
-const REPO_TOKEN_PATTERN = /\$\{(project|repo)\}/g;
+const REPO_TOKEN_PATTERN = /\${(project|repo)}/g;
// Polymer makes `app` intrinsically defined on the window by virtue of the
// custom element having the id "app", but it is made explicit here.
@@ -210,15 +208,13 @@
// Setup listeners outside of the router component initialization.
(function() {
- const reporting = document.createElement('gr-reporting');
-
window.addEventListener('WebComponentsReady', () => {
- reporting.timeEnd('WebComponentsReady');
+ appContext.reportingService.timeEnd('WebComponentsReady');
});
})();
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRouter extends mixinBehaviors( [
BaseUrlBehavior,
@@ -247,6 +243,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
start() {
if (!this._app) { return; }
this._startRouter();
@@ -716,7 +717,7 @@
(ctx, next) => this._loadUserMiddleware(ctx, next),
(ctx, next) => this._queryStringMiddleware(ctx, next),
data => {
- this.$.reporting.locationChanged(handlerName);
+ this.reporting.locationChanged(handlerName);
const promise = opt_authRedirect ?
this._redirectIfNotLoggedIn(data) : Promise.resolve();
promise.then(() => { this[handlerName](data); });
@@ -738,7 +739,7 @@
page.exit('*', (ctx, next) => {
if (!this._isRedirecting) {
- this.$.reporting.beforeLocationChanged();
+ this.reporting.beforeLocationChanged();
}
this._isRedirecting = false;
this._isInitialLoad = false;
@@ -1089,7 +1090,7 @@
project,
dashboard: decodeURIComponent(data.params[1]),
});
- this.$.reporting.setRepoName(project);
+ this.reporting.setRepoName(project);
}
_handleGroupInfoRoute(data) {
@@ -1170,7 +1171,7 @@
detail: GerritNav.RepoDetailView.COMMANDS,
repo,
});
- this.$.reporting.setRepoName(repo);
+ this.reporting.setRepoName(repo);
}
_handleRepoAccessRoute(data) {
@@ -1180,7 +1181,7 @@
detail: GerritNav.RepoDetailView.ACCESS,
repo,
});
- this.$.reporting.setRepoName(repo);
+ this.reporting.setRepoName(repo);
}
_handleRepoDashboardsRoute(data) {
@@ -1190,7 +1191,7 @@
detail: GerritNav.RepoDetailView.DASHBOARDS,
repo,
});
- this.$.reporting.setRepoName(repo);
+ this.reporting.setRepoName(repo);
}
_handleBranchListOffsetRoute(data) {
@@ -1296,7 +1297,7 @@
view: GerritNav.View.REPO,
repo,
});
- this.$.reporting.setRepoName(repo);
+ this.reporting.setRepoName(repo);
}
_handlePluginListOffsetRoute(data) {
@@ -1359,7 +1360,7 @@
queryMap: ctx.queryMap,
};
- this.$.reporting.setRepoName(params.project);
+ this.reporting.setRepoName(params.project);
this._redirectOrNavigate(params);
}
@@ -1379,7 +1380,7 @@
params.leftSide = address.leftSide;
params.lineNum = address.lineNum;
}
- this.$.reporting.setRepoName(params.project);
+ this.reporting.setRepoName(params.project);
this._redirectOrNavigate(params);
}
@@ -1430,7 +1431,7 @@
lineNum: ctx.hash,
view: GerritNav.View.EDIT,
});
- this.$.reporting.setRepoName(project);
+ this.reporting.setRepoName(project);
}
_handleChangeEditRoute(ctx) {
@@ -1443,7 +1444,7 @@
view: GerritNav.View.CHANGE,
edit: true,
});
- this.$.reporting.setRepoName(project);
+ this.reporting.setRepoName(project);
}
/**
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_html.js b/polygerrit-ui/app/elements/core/gr-router/gr-router_html.js
index 07f067e..8aa0835 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_html.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_html.js
@@ -18,5 +18,4 @@
export const htmlTemplate = html`
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
index f638f14..02b4efd 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../../../styles/shared-styles.js';
@@ -114,7 +113,7 @@
const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+\s*/g;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrSearchBar extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
index 3b37e09..9e5fdfe 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
@@ -26,12 +26,6 @@
<script src="/components/wct-browser-legacy/browser.js"></script>
<script src="/node_modules/page/page.js"></script>
-<script type="module">
-import '../../../test/common-test-setup.js';
-import './gr-search-bar.js';
-void (0);
-</script>
-
<test-fixture id="basic">
<template>
<gr-search-bar></gr-search-bar>
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.js b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.js
index dcece30..f6221c8 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.js
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-search-bar/gr-search-bar.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -31,7 +29,7 @@
const ME_EXPRESSION = 'me';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrSmartSearch extends mixinBehaviors( [
DisplayNameBehavior,
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
index e2dda2f..16dee09 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-dialog/gr-dialog.js';
@@ -29,7 +27,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrApplyFixDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -120,10 +118,9 @@
.getRobotCommentFixPreview(this.changeNum, this._patchNum, fixId)
.then(res => {
if (res != null) {
- const previews = Object.keys(res).map(key => {
+ this._currentPreviews = Object.keys(res).map(key => {
return {filepath: key, preview: res[key]};
});
- this._currentPreviews = previews;
}
})
.catch(err => {
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
index 8874f71..65958c8 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
@@ -21,12 +21,6 @@
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/components/wct-browser-legacy/browser.js"></script>
-<script type="module">
-import '../../../test/common-test-setup.js';
-import '../../../test/common-test-setup.js';
-import './gr-apply-fix-dialog.js';
-void (0);
-</script>
<test-fixture id='basic'>
<template>
@@ -36,7 +30,6 @@
<script type="module">
import '../../../test/common-test-setup.js';
-import '../../../test/common-test-setup.js';
import './gr-apply-fix-dialog.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
index 3f7da5a..040b0bd 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-comment-api_html.js';
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
const PARENT = 'PARENT';
@@ -47,12 +45,33 @@
this._getParentIndex =
PatchSetBehavior.getParentIndex;
- this._comments = comments || {};
- this._robotComments = robotComments || {};
- this._drafts = drafts || {};
+ this._comments = this._addPath(comments);
+ this._robotComments = this._addPath(robotComments);
+ this._drafts = this._addPath(drafts);
this._changeNum = changeNum;
}
+ /**
+ * Add path info to every comment as CommentInfo returned
+ * from server does not have that.
+ *
+ * TODO(taoalpha): should consider changing BE to send path
+ * back within CommentInfo
+ *
+ * @param {Object} - map between file path and comments
+ */
+ _addPath(comments = {}) {
+ const updatedComments = {};
+ for (const filePath of Object.keys(comments)) {
+ const allCommentsForPath = comments[filePath] || [];
+ if (allCommentsForPath.length) {
+ updatedComments[filePath] = allCommentsForPath
+ .map(comment => { return {...comment, path: filePath}; });
+ }
+ }
+ return updatedComments;
+ }
+
get comments() {
return this._comments;
}
@@ -160,19 +179,17 @@
const paths = this.getPaths();
const publishedComments = {};
for (const path of Object.keys(paths)) {
- let commentsToAdd = this.getAllCommentsForPath(path, opt_patchNum);
- if (opt_includeDrafts) {
- const drafts = this.getAllDraftsForPath(path, opt_patchNum)
- .map(d => Object.assign({__draft: true}, d));
- commentsToAdd = commentsToAdd.concat(drafts);
- }
- publishedComments[path] = commentsToAdd;
+ publishedComments[path] = this.getAllCommentsForPath(
+ path,
+ opt_patchNum,
+ opt_includeDrafts
+ );
}
return publishedComments;
}
/**
- * Gets all the comments and robot comments for the given change.
+ * Gets all the drafts for the given change.
*
* @param {number=} opt_patchNum
* @return {!Object}
@@ -189,6 +206,9 @@
/**
* Get the comments (robot comments) for a path and optional patch num.
*
+ * This method will always return a new shallow copy of all comments,
+ * so manipulation on one copy won't affect other copies.
+ *
* @param {!string} path
* @param {number=} opt_patchNum
* @param {boolean=} opt_includeDrafts
@@ -200,14 +220,15 @@
const robotComments = this._robotComments[path] || [];
let allComments = comments.concat(robotComments);
if (opt_includeDrafts) {
- const drafts = this.getAllDraftsForPath(path)
- .map(d => Object.assign({__draft: true}, d));
+ const drafts = this.getAllDraftsForPath(path);
allComments = allComments.concat(drafts);
}
- if (!opt_patchNum) { return allComments; }
- return (allComments || []).filter(c =>
- this._patchNumEquals(c.patch_set, opt_patchNum)
- );
+ if (opt_patchNum) {
+ allComments = allComments.filter(c =>
+ this._patchNumEquals(c.patch_set, opt_patchNum)
+ );
+ }
+ return allComments.map(c => { return {...c}; });
}
/**
@@ -215,7 +236,7 @@
*
* // TODO(taoalpha): maybe merge in *ForPath
*
- * @param {!{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {!{path: string, basePath?: string, patchNum?: number}} file
* @param {boolean=} opt_includeDrafts
* @return {!Array}
*/
@@ -224,10 +245,10 @@
file.path, file.patchNum, opt_includeDrafts
);
- if (file.oldPath) {
+ if (file.basePath) {
allComments = allComments.concat(
this.getAllCommentsForPath(
- file.oldPath, file.patchNum, opt_includeDrafts
+ file.basePath, file.patchNum, opt_includeDrafts
)
);
}
@@ -238,17 +259,22 @@
/**
* Get the drafts for a path and optional patch num.
*
+ * This will return a shallow copy of all drafts every time,
+ * so changes on any copy will not affect other copies.
+ *
* @param {!string} path
* @param {number=} opt_patchNum
* @return {!Array}
*/
getAllDraftsForPath(path,
opt_patchNum) {
- const comments = this._drafts[path] || [];
- if (!opt_patchNum) { return comments; }
- return (comments || []).filter(c =>
- this._patchNumEquals(c.patch_set, opt_patchNum)
- );
+ let comments = this._drafts[path] || [];
+ if (opt_patchNum) {
+ comments = comments.filter(c =>
+ this._patchNumEquals(c.patch_set, opt_patchNum)
+ );
+ }
+ return comments.map(c => { return {...c, __draft: true}; });
}
/**
@@ -256,14 +282,14 @@
*
* // TODO(taoalpha): maybe merge in *ForPath
*
- * @param {!{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {!{path: string, basePath?: string, patchNum?: number}} file
* @return {!Array}
*/
getAllDraftsForFile(file) {
let allDrafts = this.getAllDraftsForPath(file.path, file.patchNum);
- if (file.oldPath) {
+ if (file.basePath) {
allDrafts = allDrafts.concat(
- this.getAllDraftsForPath(file.oldPath, file.patchNum)
+ this.getAllDraftsForPath(file.basePath, file.patchNum)
);
}
return allDrafts;
@@ -298,7 +324,8 @@
drafts.forEach(d => { d.__draft = true; });
- const all = comments.concat(drafts).concat(robotComments);
+ const all = comments.concat(drafts).concat(robotComments)
+ .map(c => { return {...c}; });
const baseComments = all.filter(c =>
this._isInBaseOfPatchRange(c, patchRange));
@@ -324,7 +351,7 @@
*
* // TODO(taoalpha): maybe merge *ForPath so find all comments in one pass
*
- * @param {!{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {!{path: string, basePath?: string, patchNum?: number}} file
* @param {!Gerrit.PatchRange} patchRange The patch-range object containing patchNum
* and basePatchNum properties to represent the range.
* @param {Object=} opt_projectConfig Optional project config object to
@@ -335,13 +362,13 @@
const comments = this.getCommentsBySideForPath(
file.path, patchRange, opt_projectConfig
);
- if (file.oldPath) {
- const commentsForOldPath = this.getCommentsBySideForPath(
- file.oldPath, patchRange, opt_projectConfig
+ if (file.basePath) {
+ const commentsForBasePath = this.getCommentsBySideForPath(
+ file.basePath, patchRange, opt_projectConfig
);
// merge in the left and right
- comments.left = comments.left.concat(commentsForOldPath.left);
- comments.right = comments.right.concat(commentsForOldPath.right);
+ comments.left = comments.left.concat(commentsForBasePath.left);
+ comments.right = comments.right.concat(commentsForBasePath.right);
}
return comments;
}
@@ -376,7 +403,7 @@
/**
* Computes a string counting the number of commens in a given file.
*
- * @param {{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {{path: string, basePath?: string, patchNum?: number}} file
* @return {number}
*/
computeCommentCount(file) {
@@ -391,7 +418,7 @@
* Computes a string counting the number of draft comments in the entire
* change, optionally filtered by path and/or patchNum.
*
- * @param {?{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {?{path: string, basePath?: string, patchNum?: number}} file
* @return {number}
*/
computeDraftCount(file) {
@@ -405,7 +432,7 @@
/**
* Computes a number of unresolved comment threads in a given file and path.
*
- * @param {{path: string, oldPath?: string, patchNum?: number}} file
+ * @param {{path: string, basePath?: string, patchNum?: number}} file
* @return {number}
*/
computeUnresolvedNum(file) {
@@ -443,7 +470,7 @@
.sort(
(c1, c2) => {
const dateDiff =
- util.parseDate(c1.updated) - util.parseDate(c2.updated);
+ parseDate(c1.updated) - parseDate(c2.updated);
if (dateDiff) {
return dateDiff;
}
@@ -514,12 +541,9 @@
return true;
}
// If the base of the range is not the parent of the patch:
- if (range.basePatchNum !== PARENT &&
- comment.side !== PARENT &&
- this._patchNumEquals(comment.patch_set, range.basePatchNum)) {
- return true;
- }
- return false;
+ return range.basePatchNum !== PARENT &&
+ comment.side !== PARENT &&
+ this._patchNumEquals(comment.patch_set, range.basePatchNum);
}
/**
@@ -550,7 +574,7 @@
}
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCommentApi extends mixinBehaviors( [
PatchSetBehavior,
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
index 29262e3..172a342 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
@@ -370,16 +370,24 @@
test('getAllCommentsForPath', () => {
let path = 'file/one';
let comments = element._changeComments.getAllCommentsForPath(path);
- assert.deepEqual(comments.length, 4);
+ assert.equal(comments.length, 4);
path = 'file/two';
comments = element._changeComments.getAllCommentsForPath(path, 2);
- assert.deepEqual(comments.length, 1);
+ assert.equal(comments.length, 1);
+ const aCopyOfComments = element._changeComments
+ .getAllCommentsForPath(path, 2);
+ assert.deepEqual(comments, aCopyOfComments);
+ assert.notEqual(comments[0], aCopyOfComments[0]);
});
test('getAllDraftsForPath', () => {
const path = 'file/one';
const drafts = element._changeComments.getAllDraftsForPath(path);
- assert.deepEqual(drafts.length, 2);
+ assert.equal(drafts.length, 2);
+ const aCopyOfDrafts = element._changeComments
+ .getAllDraftsForPath(path);
+ assert.deepEqual(drafts, aCopyOfDrafts);
+ assert.notEqual(drafts[0], aCopyOfDrafts[0]);
});
test('computeUnresolvedNum', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.js b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.js
index cdd6d8f..86537e8 100644
--- a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.js
+++ b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
@@ -29,7 +27,7 @@
[CoverageType.NOT_INSTRUMENTED, 'Not instrumented by any tests.'],
]);
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCoverageLayer extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.js
index b38543c..1c4edec 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-coverage-layer/gr-coverage-layer.js';
import '../gr-diff-processor/gr-diff-processor.js';
import '../../shared/gr-hovercard/gr-hovercard.js';
@@ -46,7 +44,7 @@
const COMMIT_MSG_LINE_LENGTH = 72;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffBuilderElement extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.html
index e5eec8d..67418e2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.html
@@ -52,7 +52,7 @@
import '../gr-diff/gr-diff-group.js';
import './gr-diff-builder.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
-import {getMockDiffResponse} from '../../../test/mock-diff-response.js';
+import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-diff-builder-element.js';
import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation.js';
@@ -96,44 +96,70 @@
assert.isTrue(node.classList.contains('classes'));
});
- test('context control buttons', () => {
- // Create 10 lines.
- const lines = [];
- for (let i = 0; i < 10; i++) {
- const line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = i + 1;
- line.afterNumber = i + 1;
- line.text = 'lorem upsum';
- lines.push(line);
+ suite('context control', () => {
+ function createContextLine(options) {
+ const offset = options.offset || 0;
+ const numLines = options.count || 10;
+ const lines = [];
+ for (let i = 0; i < numLines; i++) {
+ const line = new GrDiffLine(GrDiffLine.Type.BOTH);
+ line.beforeNumber = offset + i + 1;
+ line.afterNumber = offset + i + 1;
+ line.text = 'lorem upsum';
+ lines.push(line);
+ }
+
+ return {
+ contextGroups: [new GrDiffGroup(GrDiffGroup.Type.BOTH, lines)],
+ };
}
- const contextLine = {
- contextGroups: [new GrDiffGroup(GrDiffGroup.Type.BOTH, lines)],
- };
+ test('no +10 buttons for 10 or less lines', () => {
+ const contextLine = createContextLine({count: 10});
- const section = {};
- // Does not include +10 buttons when there are fewer than 11 lines.
- let td = builder._createContextControl(section, contextLine);
- let buttons = td.querySelectorAll('gr-button.showContext');
+ const td = builder._createContextControl({}, contextLine);
+ const buttons = td.querySelectorAll('gr-button.showContext');
- assert.equal(buttons.length, 1);
- assert.equal(dom(buttons[0]).textContent, 'Show 10 common lines');
+ assert.equal(buttons.length, 1);
+ assert.equal(dom(buttons[0]).textContent, 'Show 10 common lines');
+ });
- // Add another line.
- const line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.text = 'lorem upsum';
- line.beforeNumber = 11;
- line.afterNumber = 11;
- contextLine.contextGroups[0].addLine(line);
+ test('context control at the top', () => {
+ const contextLine = createContextLine({offset: 0, count: 20});
- // Includes +10 buttons when there are at least 11 lines.
- td = builder._createContextControl(section, contextLine);
- buttons = td.querySelectorAll('gr-button.showContext');
+ builder._numLinesLeft = 50;
+ const td = builder._createContextControl({}, contextLine);
+ const buttons = td.querySelectorAll('gr-button.showContext');
- assert.equal(buttons.length, 3);
- assert.equal(dom(buttons[0]).textContent, '+10 above');
- assert.equal(dom(buttons[1]).textContent, 'Show 11 common lines');
- assert.equal(dom(buttons[2]).textContent, '+10 below');
+ assert.equal(buttons.length, 2);
+ assert.equal(dom(buttons[0]).textContent, 'Show 20 common lines');
+ assert.equal(dom(buttons[1]).textContent, '+10 below');
+ });
+
+ test('context control in the middle', () => {
+ const contextLine = createContextLine({offset: 10, count: 20});
+
+ builder._numLinesLeft = 50;
+ const td = builder._createContextControl({}, contextLine);
+ const buttons = td.querySelectorAll('gr-button.showContext');
+
+ assert.equal(buttons.length, 3);
+ assert.equal(dom(buttons[0]).textContent, '+10 above');
+ assert.equal(dom(buttons[1]).textContent, 'Show 20 common lines');
+ assert.equal(dom(buttons[2]).textContent, '+10 below');
+ });
+
+ test('context control at the top', () => {
+ const contextLine = createContextLine({offset: 30, count: 20});
+
+ builder._numLinesLeft = 50;
+ const td = builder._createContextControl({}, contextLine);
+ const buttons = td.querySelectorAll('gr-button.showContext');
+
+ assert.equal(buttons.length, 2);
+ assert.equal(dom(buttons[0]).textContent, '+10 above');
+ assert.equal(dom(buttons[1]).textContent, 'Show 20 common lines');
+ });
});
test('newlines 1', () => {
@@ -263,7 +289,6 @@
expectTextLength('abc\t', 8, 8);
expectTextLength('abc\t\t', 10, 20);
expectTextLength('', 10, 0);
- expectTextLength('', 10, 0);
// 17 Thai combining chars.
expectTextLength('ก้้้้้้้้้้้้้้้้', 4, 17);
expectTextLength('abc\tde', 10, 12);
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 1fc0d4f..6983af0 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
@@ -16,6 +16,7 @@
*/
import {GrDiffBuilderSideBySide} from './gr-diff-builder-side-by-side.js';
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
// MIME types for images we allow showing. Do not include SVG, it can contain
// arbitrary JavaScript.
@@ -52,7 +53,7 @@
// column limit.
td.setAttribute('colspan', '4');
const endpoint = this._createElement('gr-endpoint-decorator');
- const endpointDomApi = Polymer.dom(endpoint);
+ const endpointDomApi = dom(endpoint);
endpointDomApi.setAttribute('name', 'image-diff');
endpointDomApi.appendChild(
this._createEndpointParam('baseImage', this._baseImage));
@@ -106,7 +107,7 @@
GrDiffBuilderImage.prototype._updateImageLabel = function(section, className,
image) {
- const label = Polymer.dom(section)
+ const label = dom(section)
.querySelector('.' + className + ' span.label');
this._setLabelText(label, image);
};
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 4b91000..74a4591 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
@@ -16,6 +16,7 @@
*/
import {GrDiffLine} from '../gr-diff/gr-diff-line.js';
import {GrDiffGroup} from '../gr-diff/gr-diff-group.js';
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
/**
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
@@ -41,6 +42,11 @@
export function GrDiffBuilder(diff, prefs, outputEl, layers) {
this._diff = diff;
+ this._numLinesLeft = this._diff.content ? this._diff.content.reduce(
+ (sum, chunk) => {
+ const left = chunk.a || chunk.ab;
+ return sum + (left ? left.length : 0);
+ }, 0) : 0;
this._prefs = prefs;
this._outputEl = outputEl;
this.groups = [];
@@ -142,7 +148,7 @@
GrDiffBuilder.prototype.getContentByLine = function(lineNumber, opt_side,
opt_root) {
- const root = Polymer.dom(opt_root || this._outputEl);
+ const root = dom(opt_root || this._outputEl);
const sideSelector = opt_side ? ('.' + opt_side) : '';
return root.querySelector('td.lineNum[data-value="' + lineNumber +
'"]' + sideSelector + ' ~ td.content .contentText');
@@ -221,16 +227,18 @@
GrDiffBuilder.prototype._createContextControl = function(section, line) {
if (!line.contextGroups) return null;
- const numLines =
- line.contextGroups[line.contextGroups.length - 1].lineRange.left.end -
- line.contextGroups[0].lineRange.left.start + 1;
+ const leftStart = line.contextGroups[0].lineRange.left.start;
+ const leftEnd =
+ line.contextGroups[line.contextGroups.length - 1].lineRange.left.end;
+
+ const numLines = leftEnd - leftStart + 1;
if (numLines === 0) return null;
const td = this._createElement('td');
const showPartialLinks = numLines > PARTIAL_CONTEXT_AMOUNT;
- if (showPartialLinks) {
+ if (showPartialLinks && leftStart > 1) {
td.appendChild(this._createContextButton(
GrDiffBuilder.ContextButtonType.ABOVE, section, line, numLines));
}
@@ -238,7 +246,7 @@
td.appendChild(this._createContextButton(
GrDiffBuilder.ContextButtonType.ALL, section, line, numLines));
- if (showPartialLinks) {
+ if (showPartialLinks && leftEnd < this._numLinesLeft) {
td.appendChild(this._createContextButton(
GrDiffBuilder.ContextButtonType.BELOW, section, line, numLines));
}
@@ -259,7 +267,7 @@
if (type === GrDiffBuilder.ContextButtonType.ALL) {
const icon = this._createElement('iron-icon', 'showContext');
icon.setAttribute('icon', 'gr-icons:unfold-more');
- Polymer.dom(button).appendChild(icon);
+ dom(button).appendChild(icon);
text = 'Show ' + numLines + ' common line';
if (numLines > 1) { text += 's'; }
@@ -274,8 +282,8 @@
0, numLines - context);
}
const textSpan = this._createElement('span', 'showContext');
- Polymer.dom(textSpan).textContent = text;
- Polymer.dom(button).appendChild(textSpan);
+ dom(textSpan).textContent = text;
+ dom(button).appendChild(textSpan);
button.addEventListener('tap', e => {
e.detail = {
@@ -533,7 +541,7 @@
* @return {HTMLTableDataCellElement}
*/
GrDiffBuilder.prototype._getBlameByLineNum = function(lineNum) {
- const root = Polymer.dom(this._outputEl);
+ const root = dom(this._outputEl);
return root.querySelector(`td.blame[data-line-number="${lineNum}"]`);
};
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
index 0b9ae5b..acb8f0c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-cursor-manager/gr-cursor-manager.js';
import {afterNextRender} from '@polymer/polymer/lib/utils/render-status.js';
@@ -23,6 +22,7 @@
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-diff-cursor_html.js';
+import {ScrollMode} from '../../../constants/constants.js';
const DiffSides = {
LEFT: 'left',
@@ -34,15 +34,10 @@
UNIFIED: 'UNIFIED_DIFF',
};
-const ScrollBehavior = {
- KEEP_VISIBLE: 'keep-visible',
- NEVER: 'never',
-};
-
const LEFT_SIDE_CLASS = 'target-side-left';
const RIGHT_SIDE_CLASS = 'target-side-right';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrDiffCursor extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
static get template() { return htmlTemplate; }
@@ -93,9 +88,9 @@
* 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
* the viewport.
*/
- _scrollBehavior: {
+ _scrollMode: {
type: String,
- value: ScrollBehavior.KEEP_VISIBLE,
+ value: ScrollMode.KEEP_VISIBLE,
},
_focusOnMove: {
@@ -294,10 +289,9 @@
reInitCursor() {
if (!this.diffRow) {
// does not scroll during init unless requested
- const scrollingBehaviorForInit = this.initialLineNumber ?
- ScrollBehavior.KEEP_VISIBLE :
- ScrollBehavior.NEVER;
- this._scrollBehavior = scrollingBehaviorForInit;
+ this._scrollMode = this.initialLineNumber ?
+ ScrollMode.KEEP_VISIBLE :
+ ScrollMode.NEVER;
if (this.initialLineNumber) {
this.moveToLineNumber(this.initialLineNumber, this.side);
this.initialLineNumber = null;
@@ -309,17 +303,22 @@
}
reInit() {
- this._scrollBehavior = ScrollBehavior.KEEP_VISIBLE;
+ this._scrollMode = ScrollMode.KEEP_VISIBLE;
}
_handleWindowScroll() {
if (this._preventAutoScrollOnManualScroll) {
- this._scrollBehavior = ScrollBehavior.NEVER;
+ this._scrollMode = ScrollMode.NEVER;
this._focusOnMove = false;
this._preventAutoScrollOnManualScroll = false;
}
}
+ reInitAndUpdateStops() {
+ this.reInit();
+ this._updateStops();
+ }
+
handleDiffUpdate() {
this._updateStops();
this.reInitCursor();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.js
index 1ac47f6..e400792 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.js
@@ -19,7 +19,7 @@
export const htmlTemplate = html`
<gr-cursor-manager
id="cursorManager"
- scroll-behavior="[[_scrollBehavior]]"
+ scroll-mode="[[_scrollMode]]"
cursor-target-class="target-row"
focus-on-move="[[_focusOnMove]]"
target="{{diffRow}}"
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 77e5179..71fc341 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
@@ -44,7 +44,7 @@
import '../gr-diff/gr-diff.js';
import './gr-diff-cursor.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
-import {getMockDiffResponse} from '../../../test/mock-diff-response.js';
+import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
suite('gr-diff-cursor tests', () => {
let sandbox;
@@ -117,20 +117,20 @@
});
test('cursor scroll behavior', () => {
- assert.equal(cursorElement._scrollBehavior, 'keep-visible');
+ assert.equal(cursorElement._scrollMode, 'keep-visible');
cursorElement._handleDiffRenderStart();
assert.isTrue(cursorElement._focusOnMove);
cursorElement._handleWindowScroll();
- assert.equal(cursorElement._scrollBehavior, 'never');
+ assert.equal(cursorElement._scrollMode, 'never');
assert.isFalse(cursorElement._focusOnMove);
cursorElement._handleDiffRenderContent();
assert.isTrue(cursorElement._focusOnMove);
cursorElement.reInitCursor();
- assert.equal(cursorElement._scrollBehavior, 'keep-visible');
+ assert.equal(cursorElement._scrollMode, 'keep-visible');
});
test('moves to selected line', () => {
@@ -237,7 +237,7 @@
cursorElement.moveToNextChunk();
// Since this chunk only has content on the left side. we should have been
- // automatically mvoed over.
+ // automatically moved over.
const previousIndex = currentIndex;
currentIndex = indexOfChunk(cursorElement.diffRow.parentElement);
assert.equal(currentIndex, previousIndex + 1);
@@ -248,7 +248,7 @@
let scrollBehaviorDuringMove;
const moveToNumStub = sandbox.stub(cursorElement, 'moveToLineNumber');
const moveToChunkStub = sandbox.stub(cursorElement, 'moveToFirstChunk',
- () => { scrollBehaviorDuringMove = cursorElement._scrollBehavior; });
+ () => { scrollBehaviorDuringMove = cursorElement._scrollMode; });
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
@@ -256,7 +256,7 @@
assert.isFalse(moveToNumStub.called);
assert.isTrue(moveToChunkStub.called);
assert.equal(scrollBehaviorDuringMove, 'never');
- assert.equal(cursorElement._scrollBehavior, 'keep-visible');
+ assert.equal(cursorElement._scrollMode, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
@@ -266,7 +266,7 @@
test('initialLineNumber provided', done => {
let scrollBehaviorDuringMove;
const moveToNumStub = sandbox.stub(cursorElement, 'moveToLineNumber',
- () => { scrollBehaviorDuringMove = cursorElement._scrollBehavior; });
+ () => { scrollBehaviorDuringMove = cursorElement._scrollMode; });
const moveToChunkStub = sandbox.stub(cursorElement, 'moveToFirstChunk');
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
@@ -276,7 +276,7 @@
assert.equal(moveToNumStub.lastCall.args[0], 10);
assert.equal(moveToNumStub.lastCall.args[1], 'right');
assert.equal(scrollBehaviorDuringMove, 'keep-visible');
- assert.equal(cursorElement._scrollBehavior, 'keep-visible');
+ assert.equal(cursorElement._scrollMode, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
index 4006d13..c86760a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
@@ -14,6 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+import {sanitizeDOMValue} from '@polymer/polymer/lib/utils/settings.js';
// TODO(wyatta): refactor this to be <MARK> rather than <HL>.
const ANNOTATION_TAG = 'HL';
@@ -84,7 +86,7 @@
}
const wrapper = document.createElement(tagName);
- const sanitizer = window.Polymer.sanitizeDOMValue;
+ const sanitizer = sanitizeDOMValue;
for (const [name, value] of Object.entries(attributes)) {
wrapper.setAttribute(
name, sanitizer ?
@@ -149,8 +151,8 @@
} else {
hl = document.createElement(ANNOTATION_TAG);
hl.className = cssClass;
- Polymer.dom(node.parentElement).replaceChild(hl, node);
- Polymer.dom(hl).appendChild(node);
+ dom(node.parentElement).replaceChild(hl, node);
+ dom(hl).appendChild(node);
}
return hl;
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
index 53b416b..c5dab43 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../gr-selection-action-box/gr-selection-action-box.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -27,7 +25,7 @@
import {GrRangeNormalizer} from './gr-range-normalizer.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffHighlight extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -340,12 +338,9 @@
}
const start = range.start;
const end = range.end;
- if (start.side !== end.side ||
+ return !(start.side !== end.side ||
end.line < start.line ||
- (start.line === end.line && start.column === end.column)) {
- return false;
- }
- return true;
+ (start.line === end.line && start.column === end.column));
}
_handleSelection(selection, isMouseUp) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_html.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_html.js
index 08b21499..afd4ac5 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_html.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_html.js
@@ -23,7 +23,7 @@
}
gr-selection-action-box {
/**
- * Needs z-index to apear above wrapped content, since it's inseted
+ * Needs z-index to appear above wrapped content, since it's inserted
* into DOM before it.
*/
z-index: 10;
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 2ed69b6..b367265 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
@@ -14,9 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../../shared/gr-comment-thread/gr-comment-thread.js';
import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
@@ -30,9 +27,10 @@
import {htmlTemplate} from './gr-diff-host_html.js';
import {PatchSetBehavior} from '../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.js';
import {GrDiffBuilder} from '../gr-diff-builder/gr-diff-builder.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {DiffSide, rangesEqual} from '../gr-diff/gr-diff-utils.js';
+import {appContext} from '../../../services/app-context.js';
const MSG_EMPTY_BLAME = 'No blame information for this diff.';
@@ -85,7 +83,7 @@
* Webcomponent fetching diffs and related data from restAPI and passing them
* to the presentational gr-diff for rendering.
*
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffHost extends mixinBehaviors( [
PatchSetBehavior,
@@ -122,6 +120,9 @@
},
/** @type {?} */
patchRange: Object,
+ /** @type {!Gerrit.FileRange} */
+ file: Object,
+ // TODO: deprecate path since that info is included in file
path: String,
prefs: {
type: Object,
@@ -259,6 +260,11 @@
];
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -360,21 +366,21 @@
const needsSyntaxHighlighting = event.detail &&
event.detail.contentRendered;
if (needsSyntaxHighlighting) {
- this.$.reporting.time(TimingLabel.SYNTAX);
+ this.reporting.time(TimingLabel.SYNTAX);
this.$.syntaxLayer.process().then(() => {
- this.$.reporting.timeEnd(TimingLabel.SYNTAX);
- this.$.reporting.timeEnd(TimingLabel.TOTAL);
+ this.reporting.timeEnd(TimingLabel.SYNTAX);
+ this.reporting.timeEnd(TimingLabel.TOTAL);
resolve();
});
} else {
- this.$.reporting.timeEnd(TimingLabel.TOTAL);
+ this.reporting.timeEnd(TimingLabel.TOTAL);
resolve();
}
this.removeEventListener('render', callback);
if (shouldReportMetric) {
// We report diffViewContentDisplayed only on reload caused
// by params changed - expected only on Diff Page.
- this.$.reporting.diffViewContentDisplayed();
+ this.reporting.diffViewContentDisplayed();
}
};
this.addEventListener('render', callback);
@@ -602,11 +608,11 @@
// Report the due_to_rebase percentage in the "diff" category when
// applicable.
if (this.patchRange.basePatchNum === 'PARENT') {
- this.$.reporting.reportInteraction(EVENT_AGAINST_PARENT);
+ this.reporting.reportInteraction(EVENT_AGAINST_PARENT);
} else if (percentRebaseDelta === 0) {
- this.$.reporting.reportInteraction(EVENT_ZERO_REBASE);
+ this.reporting.reportInteraction(EVENT_ZERO_REBASE);
} else {
- this.$.reporting.reportInteraction(EVENT_NONZERO_REBASE,
+ this.reporting.reportInteraction(EVENT_NONZERO_REBASE,
{percentRebaseDelta});
}
}
@@ -661,7 +667,7 @@
return comments.slice(0).sort((a, b) => {
if (b.__draft && !a.__draft ) { return -1; }
if (a.__draft && !b.__draft ) { return 1; }
- return util.parseDate(a.updated) - util.parseDate(b.updated);
+ return parseDate(a.updated) - parseDate(b.updated);
});
}
@@ -726,7 +732,7 @@
isOnParent);
threadEl.addOrEditDraft(lineNum, range);
- this.$.reporting.recordDraftInteraction();
+ this.reporting.recordDraftInteraction();
}
/**
@@ -775,6 +781,15 @@
threadEl.commentSide = thread.commentSide;
threadEl.isOnParent = !!thread.isOnParent;
threadEl.parentIndex = this._parentIndex;
+ // Use path before renmaing when comment added on the left when comparing
+ // two patch sets (not against base)
+ if (this.file && this.file.basePath
+ && thread.commentSide === GrDiffBuilder.Side.LEFT
+ && !thread.isOnParent) {
+ threadEl.path = this.file.basePath;
+ } else {
+ threadEl.path = this.path;
+ }
threadEl.changeNum = this.changeNum;
threadEl.patchNum = thread.patchNum;
threadEl.lineNum = thread.lineNum;
@@ -782,7 +797,6 @@
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 => {
@@ -941,7 +955,7 @@
/**
* Closure annotation for Polymer.prototype.push is off. Submitted PR:
* https://github.com/Polymer/polymer/pull/4776
- * but for not supressing annotations.
+ * but for not suppressing annotations.
*
* @suppress {checkTypes}
*/
@@ -1024,7 +1038,7 @@
_listenToViewportRender() {
const renderUpdateListener = start => {
if (start > NUM_OF_LINES_THRESHOLD_FOR_VIEWPORT) {
- this.$.reporting.diffViewDisplayed();
+ this.reporting.diffViewDisplayed();
this.$.syntaxLayer.removeListener(renderUpdateListener);
}
};
@@ -1033,16 +1047,16 @@
}
_handleRenderStart() {
- this.$.reporting.time(TimingLabel.TOTAL);
- this.$.reporting.time(TimingLabel.CONTENT);
+ this.reporting.time(TimingLabel.TOTAL);
+ this.reporting.time(TimingLabel.CONTENT);
}
_handleRenderContent() {
- this.$.reporting.timeEnd(TimingLabel.CONTENT);
+ this.reporting.timeEnd(TimingLabel.CONTENT);
}
_handleNormalizeRange(event) {
- this.$.reporting.reportInteraction('normalize-range',
+ this.reporting.reportInteraction('normalize-range',
{
side: event.detail.side,
lineNum: event.detail.lineNum,
@@ -1050,7 +1064,7 @@
}
_handleDiffContextExpanded(event) {
- this.$.reporting.reportInteraction(
+ this.reporting.reportInteraction(
'diff-context-expanded', {numLines: event.detail.numLines}
);
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.js
index 4e425dc..aa05bb5 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.js
@@ -53,5 +53,4 @@
></gr-syntax-layer>
<gr-js-api-interface id="jsAPI"></gr-js-api-interface>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting" category="diff"></gr-reporting>
`;
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 0cb2b5e..b8f26b2 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
@@ -50,11 +50,9 @@
stub('gr-rest-api-interface', {
async getLoggedIn() { return getLoggedIn; },
});
- stub('gr-reporting', {
- time: sandbox.stub(),
- timeEnd: sandbox.stub(),
- });
element = fixture('basic');
+ sandbox.stub(element.reporting, 'time');
+ sandbox.stub(element.reporting, 'timeEnd');
});
teardown(() => {
@@ -307,9 +305,9 @@
test('starts total and content timer on render-start', done => {
element.dispatchEvent(
new CustomEvent('render-start', {bubbles: true, composed: true}));
- assert.isTrue(element.$.reporting.time.calledWithExactly(
+ assert.isTrue(element.reporting.time.calledWithExactly(
'Diff Total Render'));
- assert.isTrue(element.$.reporting.time.calledWithExactly(
+ assert.isTrue(element.reporting.time.calledWithExactly(
'Diff Content Render'));
done();
});
@@ -317,11 +315,12 @@
test('ends content timer on render-content', () => {
element.dispatchEvent(
new CustomEvent('render-content', {bubbles: true, composed: true}));
- assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
+ assert.isTrue(element.reporting.timeEnd.calledWithExactly(
'Diff Content Render'));
});
test('ends total and syntax timer after syntax layer processing', done => {
+ sandbox.stub(element.reporting, 'diffViewContentDisplayed');
let notifySyntaxProcessed;
sandbox.stub(element.$.syntaxLayer, 'process').returns(new Promise(
resolve => {
@@ -339,12 +338,11 @@
notifySyntaxProcessed();
// Assert after the notification task is processed.
Promise.resolve().then(() => {
- assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
+ assert.isTrue(element.reporting.timeEnd.calledWithExactly(
'Diff Total Render'));
- assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
+ assert.isTrue(element.reporting.timeEnd.calledWithExactly(
'Diff Syntax Render'));
- assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
- 'StartupDiffViewOnlyContent'));
+ assert.isTrue(element.reporting.diffViewContentDisplayed.called);
done();
});
});
@@ -357,8 +355,8 @@
element.reload();
// Multiple cascading microtasks are scheduled.
setTimeout(() => {
- assert.isTrue(element.$.reporting.timeEnd.calledOnce);
- assert.isTrue(element.$.reporting.timeEnd.calledWithExactly(
+ assert.isTrue(element.reporting.timeEnd.calledOnce);
+ assert.isTrue(element.reporting.timeEnd.calledWithExactly(
'Diff Total Render'));
done();
});
@@ -1026,8 +1024,9 @@
setup(() => {
element = fixture('basic');
+ element.path = 'file.txt';
element.patchRange = {basePatchNum: 1};
- reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
+ reportStub = sandbox.stub(element.reporting, 'reportInteraction');
});
test('null and content-less', () => {
@@ -1330,6 +1329,54 @@
assert.equal(threads[1].patchNum, 3);
});
+ test('thread should use old file path if first created' +
+ 'on patch set (left) before renaming', () => {
+ const commentSide = 'left';
+ element.file = {basePath: 'file_renamed.txt', path: element.path};
+
+ assert.isOk(element._getOrCreateThread('2', 3,
+ commentSide, undefined, /* isOnParent= */ false));
+
+ const threads = dom(element.$.diff)
+ .queryDistributedElements('gr-comment-thread');
+
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].commentSide, commentSide);
+ assert.equal(threads[0].path, element.file.basePath);
+ });
+
+ test('thread should use new file path if first created' +
+ 'on patch set (right) after renaming', () => {
+ const commentSide = 'right';
+ element.file = {basePath: 'file_renamed.txt', path: element.path};
+
+ assert.isOk(element._getOrCreateThread('2', 3,
+ commentSide, undefined, /* isOnParent= */ false));
+
+ const threads = dom(element.$.diff)
+ .queryDistributedElements('gr-comment-thread');
+
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].commentSide, commentSide);
+ assert.equal(threads[0].path, element.file.path);
+ });
+
+ test('thread should use new file path if first created' +
+ 'on patch set (left) but is base', () => {
+ const commentSide = 'left';
+ element.file = {basePath: 'file_renamed.txt', path: element.path};
+
+ assert.isOk(element._getOrCreateThread('2', 3,
+ commentSide, undefined, /* isOnParent= */ true));
+
+ const threads = dom(element.$.diff)
+ .queryDistributedElements('gr-comment-thread');
+
+ assert.equal(threads.length, 1);
+ assert.equal(threads[0].commentSide, commentSide);
+ assert.equal(threads[0].path, element.file.path);
+ });
+
test('_filterThreadElsForLocation with no threads', () => {
const line = {beforeNumber: 3, afterNumber: 5};
@@ -1443,7 +1490,7 @@
});
});
- suite('syntax layer with syntax_highlgihting off', () => {
+ suite('syntax layer with syntax_highlighting off', () => {
setup(() => {
const prefs = {
line_length: 10,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
index acd9457..7c9d1ec 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -25,7 +23,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-diff-mode-selector_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrDiffModeSelector extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.js
index 8f48507..b68c889 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-diff-preferences/gr-diff-preferences.js';
@@ -26,7 +24,7 @@
import {htmlTemplate} from './gr-diff-preferences-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffPreferencesDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -36,7 +34,7 @@
static get properties() {
return {
- /** @type {?} */
+ /** @type {?} */
diffPrefs: Object,
/**
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_test.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_test.js
new file mode 100644
index 0000000..07cca9a
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_test.js
@@ -0,0 +1,50 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma.js';
+
+const basicFixture = fixtureFromElement('gr-diff-preferences-dialog');
+
+suite('gr-diff-preferences-dialog', () => {
+ let element;
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+ test('changes applies only on save', async () => {
+ const originalDiffPrefs = {
+ line_wrapping: true,
+ };
+ element.diffPrefs = originalDiffPrefs;
+
+ element.open();
+ await flush();
+ assert.isTrue(element.$.diffPreferences.$.lineWrappingInput.checked);
+
+ MockInteractions.tap(element.$.diffPreferences.$.lineWrappingInput);
+ await flush();
+ assert.isFalse(element.$.diffPreferences.$.lineWrappingInput.checked);
+ assert.isTrue(element._diffPrefsChanged);
+ assert.isTrue(element.diffPrefs.line_wrapping);
+ assert.isTrue(originalDiffPrefs.line_wrapping);
+
+ MockInteractions.tap(element.$.saveButton);
+ await flush();
+ // Original prefs must remains unchanged, dialog must expose a new object
+ assert.isTrue(originalDiffPrefs.line_wrapping);
+ assert.isFalse(element.diffPrefs.line_wrapping);
+ });
+});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
index 62ddfee..b9c97a9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
@@ -70,7 +68,7 @@
* that the part that is within the context or has comments is shown, while
* the rest is not.
*
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffProcessor extends GestureEventListeners(
LegacyElementMixin(
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
index 50bfe107..aafd374 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
@@ -105,7 +105,6 @@
group = groups[1];
assert.equal(group.type, GrDiffGroup.Type.BOTH);
assert.equal(group.lines.length, 2);
- assert.equal(group.lines.length, 2);
function beforeNumberFn(l) { return l.beforeNumber; }
function afterNumberFn(l) { return l.afterNumber; }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
index 08967e8..608e898 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {addListener} from '@polymer/polymer/lib/utils/gestures.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -42,7 +40,7 @@
const getNewCache = () => { return {left: null, right: null}; };
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffSelection extends mixinBehaviors( [
DomUtilBehavior,
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 e434e65..415ce1e 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
@@ -14,12 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-dropdown/iron-dropdown.js';
import '@polymer/iron-input/iron-input.js';
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-dropdown/gr-dropdown.js';
import '../../shared/gr-dropdown-list/gr-dropdown-list.js';
@@ -48,6 +45,7 @@
import {GrCountStringFormatter} from '../../shared/gr-count-string-formatter/gr-count-string-formatter.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {RevisionInfo} from '../../shared/revision-info/revision-info.js';
+import {appContext} from '../../../services/app-context.js';
const ERR_REVIEW_STATUS = 'Couldn’t change file review status.';
const MSG_LOADING_BLAME = 'Loading blame...';
@@ -67,7 +65,7 @@
/**
* @appliesMixin PatchSetMixin
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiffView extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -164,6 +162,12 @@
value() { return {sortedFileList: [], changeFilesByPath: {}}; },
},
+ /** @type {Gerrit.FileRange} */
+ _file: {
+ type: Object,
+ computed: '_getCurrentFile(_files, _path)',
+ },
+
_path: {
type: String,
observer: '_pathChanged',
@@ -237,9 +241,9 @@
* gr-diff-view has gr-fixed-panel on top. The panel can
* intersect a main element and partially hides a content of
* the main element. To correctly calculates visibility of an
- * element, the cursor must know how much height occuped by a fixed
+ * element, the cursor must know how much height occupied by a fixed
* panel.
- * The scrollTopMargin defines margin occuped by fixed panel.
+ * The scrollTopMargin defines margin occupied by fixed panel.
*/
_scrollTopMargin: {
type: Number,
@@ -301,6 +305,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
attached() {
super.attached();
@@ -345,6 +354,21 @@
return files.sortedFileList;
}
+ /**
+ * @param {!Object} files
+ * @param {string} path
+ * @returns {!Gerrit.FileRange}
+ */
+ _getCurrentFile(files, path) {
+ if ([files, path].includes(undefined)) return;
+ const fileInfo = files.changeFilesByPath[path];
+ const fileRange = {path};
+ if (fileInfo && fileInfo.old_path) {
+ fileRange.basePath = fileInfo.old_path;
+ }
+ return fileRange;
+ }
+
_getFiles(changeNum, patchRangeRecord, changeComments) {
// Polymer 2: check for undefined
if ([changeNum, patchRangeRecord, patchRangeRecord.base, changeComments]
@@ -358,10 +382,7 @@
if (!changeFiles) return;
const commentedPaths = changeComments.getPaths(patchRange);
const files = Object.assign({}, changeFiles);
- Object.keys(commentedPaths).forEach(commentedPath => {
- if (files.hasOwnProperty(commentedPath)) { return; }
- files[commentedPath] = {status: 'U'};
- });
+ this.addUnmodifiedFiles(files, commentedPaths);
this._files = {
sortedFileList: Object.keys(files).sort(this.specialFilePathCompare),
changeFilesByPath: files,
@@ -647,7 +668,10 @@
_goToEditFile() {
// TODO(taoalpha): add a shortcut for editing
const editUrl = GerritNav.getEditUrlForDiff(
- this._change, this._path, this._patchRange.patchNum);
+ this._change,
+ this._path,
+ this._patchRange.patchNum
+ );
return GerritNav.navigateToRelativeUrl(editUrl);
}
@@ -790,9 +814,14 @@
return this.$.diffHost.reload(true);
})
.then(() => {
- this.$.reporting.diffViewFullyLoaded();
+ this.reporting.diffViewFullyLoaded();
// If diff view displayed has not ended yet, it ends here.
- this.$.reporting.diffViewDisplayed();
+ this.reporting.diffViewDisplayed();
+ })
+ .then(() => {
+ // If the blame was loaded for a previous file and user navigates to
+ // another file, then we load the blame for this file too
+ if (this._isBlameLoaded) this._loadBlame();
});
}
@@ -1129,7 +1158,7 @@
const file = files[path];
if (file && file.old_path) {
this._commentsForDiff = this._changeComments.getCommentsBySideForFile(
- {path, oldPath: file.old_path},
+ {path, basePath: file.old_path},
patchRange,
projectConfig);
@@ -1209,16 +1238,7 @@
return 'Show blame';
}
- /**
- * Load and display blame information if it has not already been loaded.
- * Otherwise hide it.
- */
- _toggleBlame() {
- if (this._isBlameLoaded) {
- this.$.diffHost.clearBlame();
- return;
- }
-
+ _loadBlame() {
this._isBlameLoading = true;
this.dispatchEvent(new CustomEvent('show-alert', {
detail: {message: MSG_LOADING_BLAME},
@@ -1237,6 +1257,18 @@
});
}
+ /**
+ * Load and display blame information if it has not already been loaded.
+ * Otherwise hide it.
+ */
+ _toggleBlame() {
+ if (this._isBlameLoaded) {
+ this.$.diffHost.clearBlame();
+ return;
+ }
+ this._loadBlame();
+ }
+
_handleToggleBlame(e) {
if (this.shouldSuppressKeyboardShortcut(e) ||
this.modifierPressed(e)) { return; }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.js
index c74a192..e735153 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.js
@@ -391,6 +391,7 @@
change-num="[[_changeNum]]"
commit-range="[[_commitRange]]"
patch-range="[[_patchRange]]"
+ file="[[_file]]"
path="[[_path]]"
prefs="[[_prefs]]"
project-name="[[_change.project]]"
@@ -420,5 +421,4 @@
scroll-top-margin="[[_scrollTopMargin]]"
></gr-diff-cursor>
<gr-comment-api id="commentAPI"></gr-comment-api>
- <gr-reporting id="reporting"></gr-reporting>
`;
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 f5275e2..98371dc 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
@@ -44,6 +44,7 @@
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {KeyboardShortcutBinder} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {ChangeStatus} from '../../../constants/constants.js';
suite('gr-diff-view tests', () => {
suite('basic tests', () => {
@@ -134,7 +135,7 @@
});
test('params change triggers diffViewDisplayed()', () => {
- sandbox.stub(element.$.reporting, 'diffViewDisplayed');
+ sandbox.stub(element.reporting, 'diffViewDisplayed');
sandbox.stub(element.$.diffHost, 'reload').returns(Promise.resolve());
sandbox.spy(element, '_paramsChanged');
element.params = {
@@ -146,7 +147,28 @@
};
return element._paramsChanged.returnValues[0].then(() => {
- assert.isTrue(element.$.reporting.diffViewDisplayed.calledOnce);
+ assert.isTrue(element.reporting.diffViewDisplayed.calledOnce);
+ });
+ });
+
+ test('params change cases blame to load if it was set to true', () => {
+ // Blame loads for subsequent files if it was loaded for one file
+ element._isBlameLoaded = true;
+ sandbox.stub(element.reporting, 'diffViewDisplayed');
+ sandbox.stub(element, '_loadBlame');
+ sandbox.stub(element.$.diffHost, 'reload').returns(Promise.resolve());
+ sandbox.spy(element, '_paramsChanged');
+ element.params = {
+ view: GerritNav.View.DIFF,
+ changeNum: '42',
+ patchNum: '2',
+ basePatchNum: '1',
+ path: '/COMMIT_MSG',
+ };
+
+ return element._paramsChanged.returnValues[0].then(() => {
+ assert.isTrue(element._isBlameLoaded);
+ assert.isTrue(element._loadBlame.calledOnce);
});
});
@@ -403,7 +425,8 @@
};
element._change = {
_number: 42,
- status: 'NEW',
+ project: 'gerrit',
+ status: ChangeStatus.NEW,
revisions: {
a: {_number: 1, commit: {parents: []}},
b: {_number: 2, commit: {parents: []}},
@@ -416,6 +439,12 @@
assert.isTrue(!!editBtn);
MockInteractions.tap(editBtn);
assert.isTrue(redirectStub.called);
+ assert.isTrue(redirectStub.lastCall.calledWithExactly(
+ GerritNav.getEditUrlForDiff(
+ element._change,
+ element._path,
+ element._patchRange.patchNum
+ )));
done();
});
});
@@ -445,14 +474,14 @@
}
test('edit visible only when logged and status NEW', async () => {
- for (const changeStatus in element.ChangeStatus) {
- if (!element.ChangeStatus.hasOwnProperty(changeStatus)) {
+ for (const changeStatus in ChangeStatus) {
+ if (!ChangeStatus.hasOwnProperty(changeStatus)) {
continue;
}
assert.isFalse(await isEditVisibile({loggedIn: false, changeStatus}),
`loggedIn: false, changeStatus: ${changeStatus}`);
- if (changeStatus !== element.ChangeStatus.NEW) {
+ if (changeStatus !== ChangeStatus.NEW) {
assert.isFalse(await isEditVisibile({loggedIn: true, changeStatus}),
`loggedIn: true, changeStatus: ${changeStatus}`);
} else {
@@ -464,17 +493,17 @@
test('edit visible when logged and status NEW', async () => {
assert.isTrue(await isEditVisibile(
- {loggedIn: true, changeStatus: element.ChangeStatus.NEW}));
+ {loggedIn: true, changeStatus: ChangeStatus.NEW}));
});
test('edit hidden when logged and status ABANDONED', async () => {
assert.isFalse(await isEditVisibile(
- {loggedIn: true, changeStatus: element.ChangeStatus.ABANDONED}));
+ {loggedIn: true, changeStatus: ChangeStatus.ABANDONED}));
});
test('edit hidden when logged and status MERGED', async () => {
assert.isFalse(await isEditVisibile(
- {loggedIn: true, changeStatus: element.ChangeStatus.MERGED}));
+ {loggedIn: true, changeStatus: ChangeStatus.MERGED}));
});
suite('diff prefs hidden', () => {
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 1bb3842..bfe7325 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
import '../gr-diff-builder/gr-diff-builder-element.js';
@@ -58,7 +56,7 @@
const COMMIT_MSG_PATH = '/COMMIT_MSG';
/**
- * 72 is the inofficial length standard for git commit messages.
+ * 72 is the unofficial length standard for git commit messages.
* Derived from the fact that git log/show appends 4 ws in the beginning of
* each line when displaying commit messages. To center the commit message
* in an 80 char terminal a 4 ws border is added to the rightmost side:
@@ -69,7 +67,7 @@
const RENDER_DIFF_TABLE_DEBOUNCE_NAME = 'renderDiffTable';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDiff extends mixinBehaviors( [
PatchSetBehavior,
@@ -670,13 +668,10 @@
/** @return {boolean} */
_getIsParentCommentByLineAndContent(lineEl, contentEl) {
- if ((lineEl.classList.contains(DiffSide.LEFT) ||
+ return (lineEl.classList.contains(DiffSide.LEFT) ||
contentEl.classList.contains('remove')) &&
(this.patchRange.basePatchNum === 'PARENT' ||
- this.isMergeParent(this.patchRange.basePatchNum))) {
- return true;
- }
- return false;
+ this.isMergeParent(this.patchRange.basePatchNum));
}
/** @return {string} */
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.js
similarity index 93%
rename from polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
rename to polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
index bb0366b..d497b9a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
@@ -1,46 +1,38 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2015 The Android Open Source Project
+/**
+ * @license
+ * Copyright (C) 2015 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.
+ */
-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">
-<meta charset="utf-8">
-<title>gr-diff</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-<script src="/components/web-component-tester/data/a11ySuite.js"></script>
-
-<test-fixture id="basic">
- <template>
- <gr-diff></gr-diff>
- </template>
-</test-fixture>
-
-<script type="module">
-import '../../../test/common-test-setup.js';
+import '../../../test/common-test-setup-karma.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
-import {getMockDiffResponse} from '../../../test/mock-diff-response.js';
+import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-diff.js';
import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GrDiffBuilderImage} from '../gr-diff-builder/gr-diff-builder-image.js';
import {util} from '../../../scripts/util.js';
import {_setHiddenScroll} from '../../../scripts/hiddenscroll.js';
+import {runA11yAudit} from '../../../test/a11y-test-utils.js';
+import '@polymer/paper-button/paper-button.js';
+
+const basicFixture = fixtureFromElement('gr-diff');
+
+suite('gr-diff a11y test', () => {
+ test('audit', async () => {
+ await runA11yAudit(basicFixture);
+ });
+});
suite('gr-diff tests', () => {
let element;
@@ -62,7 +54,7 @@
};
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
sandbox.stub(element.$.highlights, 'handleSelectionChange');
});
@@ -80,21 +72,21 @@
});
test('cancel', () => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
const cancelStub = sandbox.stub(element.$.diffBuilder, 'cancel');
element.cancel();
assert.isTrue(cancelStub.calledOnce);
});
test('line limit with line_wrapping', () => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.prefs = Object.assign({}, MINIMAL_PREFS, {line_wrapping: true});
flushAsynchronousOperations();
assert.equal(util.getComputedStyleValue('--line-limit', element), '80ch');
});
test('line limit without line_wrapping', () => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.prefs = Object.assign({}, MINIMAL_PREFS, {line_wrapping: false});
flushAsynchronousOperations();
assert.isNotOk(util.getComputedStyleValue('--line-limit', element));
@@ -105,7 +97,7 @@
let contentEl;
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
lineEl = document.createElement('td');
contentEl = document.createElement('span');
});
@@ -191,7 +183,7 @@
stub('gr-rest-api-interface', {
getLoggedIn() { return getLoggedInPromise; },
});
- element = fixture('basic');
+ element = basicFixture.instantiate();
return getLoggedInPromise;
});
@@ -645,7 +637,7 @@
suite('logged in', () => {
let fakeLineEl;
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.loggedIn = true;
element.patchRange = {};
@@ -740,7 +732,7 @@
suite('diff header', () => {
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.diff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
@@ -785,7 +777,7 @@
let renderStub;
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
renderStub = sandbox.stub(element.$.diffBuilder, 'render',
() => {
element.$.diffBuilder.dispatchEvent(
@@ -837,7 +829,7 @@
suite('blame', () => {
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
});
test('unsetting', () => {
@@ -850,8 +842,7 @@
});
test('setting', () => {
- const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
- element.blame = mockBlame;
+ element.blame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
assert.isTrue(element.classList.contains('showBlame'));
});
});
@@ -864,7 +855,7 @@
element.shadowRoot.querySelector('.newlineWarning').textContent;
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.showNewlineWarningLeft = false;
element.showNewlineWarningRight = false;
});
@@ -920,7 +911,7 @@
});
test('_prefsEqual', () => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
assert.isTrue(element._prefsEqual(null, null));
assert.isTrue(element._prefsEqual({}, {}));
assert.isTrue(element._prefsEqual({x: 1}, {x: 1}));
@@ -942,7 +933,7 @@
let renderStub;
setup(() => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.prefs = {};
renderStub = sandbox.stub(element.$.diffBuilder, 'render')
.returns(new Promise(() => {}));
@@ -991,7 +982,7 @@
});
const setupSampleDiff = function(params) {
const {ignore_whitespace, content} = params;
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.prefs = {
ignore_whitespace: ignore_whitespace || 'IGNORE_ALL',
auto_hide_diff_table_header: true,
@@ -1038,9 +1029,8 @@
}
setupSampleDiff({content});
assertDiffTableWithContent();
- const diffCopy = Object.assign({}, element.diff);
- element.diff = diffCopy;
- // immediatelly cleaned up
+ element.diff = Object.assign({}, element.diff);
+ // immediately cleaned up
assert.equal(element.$.diffTable.innerHTML, '');
element._renderDiffTable();
flushAsynchronousOperations();
@@ -1151,7 +1141,7 @@
});
test('`render` event has contentRendered field in detail', done => {
- element = fixture('basic');
+ element = basicFixture.instantiate();
element.prefs = {};
sandbox.stub(element.$.diffBuilder, 'render')
.returns(Promise.resolve());
@@ -1161,7 +1151,21 @@
});
element._renderDiffTable();
});
-});
-a11ySuite('basic');
-</script>
+ test('_prefsEqual', () => {
+ element = basicFixture.instantiate();
+ assert.isTrue(element._prefsEqual(null, null));
+ assert.isTrue(element._prefsEqual({}, {}));
+ assert.isTrue(element._prefsEqual({x: 1}, {x: 1}));
+ assert.isTrue(element._prefsEqual({x: 1, abc: 'def'}, {x: 1, abc: 'def'}));
+ const somePref = {abc: 'def', p: true};
+ assert.isTrue(element._prefsEqual(somePref, somePref));
+
+ assert.isFalse(element._prefsEqual({}, null));
+ assert.isFalse(element._prefsEqual(null, {}));
+ assert.isFalse(element._prefsEqual({x: 1}, {x: 2}));
+ assert.isFalse(element._prefsEqual({x: 1, y: 'abc'}, {x: 1, y: 'abcd'}));
+ assert.isFalse(element._prefsEqual({x: 1, y: 'abc'}, {x: 1}));
+ assert.isFalse(element._prefsEqual({x: 1}, {x: 1, y: 'abc'}));
+ });
+});
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
index 8bdc1a8..3bf3697 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-dropdown-list/gr-dropdown-list.js';
import '../../shared/gr-select/gr-select.js';
@@ -38,7 +36,7 @@
*
* @property {string} patchNum
* @property {string} basePatchNum
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrPatchRangeSelect extends mixinBehaviors( [
PatchSetBehavior,
@@ -215,7 +213,7 @@
* In addition, if the current basePatchNum is 'PARENT', all patchNums are
* valid.
*
- * If the curent basePatchNum is a parent index, then only patches that have
+ * If the current basePatchNum is a parent index, then only patches that have
* at least that many parents are valid.
*
* @param {number|string} basePatchNum The current selected base patch num.
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index 63e6fc6..218ca7e 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -45,7 +45,7 @@
import '../gr-comment-api/gr-comment-api.js';
import '../../shared/revision-info/revision-info.js';
import './gr-patch-range-select.js';
-import '../gr-comment-api/gr-comment-api-mock_test.js';
+import '../../../test/mocks/comment-api.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {RevisionInfo} from '../../shared/revision-info/revision-info.js';
suite('gr-patch-range-select tests', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
index e6c49be..70aa1e7 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -24,12 +22,12 @@
import {GrDiffLine} from '../gr-diff/gr-diff-line.js';
// Polymer 1 adds # before array's key, while Polymer 2 doesn't
-const HOVER_PATH_PATTERN = /^(commentRanges\.\#?\d+)\.hovering$/;
+const HOVER_PATH_PATTERN = /^(commentRanges\.#?\d+)\.hovering$/;
const RANGE_HIGHLIGHT = 'style-scope gr-diff range';
const HOVER_HIGHLIGHT = 'style-scope gr-diff rangeHighlight';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrRangedCommentLayer extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
index f16db3b..79f937c 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../shared/gr-tooltip/gr-tooltip.js';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -25,7 +23,7 @@
import {htmlTemplate} from './gr-selection-action-box_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrSelectionActionBox extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
index f1e930f..ac5804f 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-lib-loader/gr-lib-loader.js';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -135,12 +133,12 @@
};
const CPP_DIRECTIVE_WITH_LT_PATTERN = /^\s*#(if|define).*</;
-const CPP_WCHAR_PATTERN = /L\'(\\)?.\'/g;
+const CPP_WCHAR_PATTERN = /L'(\\)?.'/g;
const JAVA_PARAM_ANNOT_PATTERN = /(@[^\s]+)\(([^)]+)\)/g;
const GO_BACKSLASH_LITERAL = '\'\\\\\'';
const GLOBAL_LT_PATTERN = /</g;
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrSyntaxLayer extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
index ccdbe8b..638b188 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
@@ -33,7 +33,7 @@
<script type="module">
import '../../../test/common-test-setup.js';
-import {getMockDiffResponse} from '../../../test/mock-diff-response.js';
+import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-syntax-layer.js';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation.js';
import {GrDiffLine} from '../gr-diff/gr-diff-line.js';
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
index 4d66699..01268b1 100644
--- 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
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-table-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-list-view/gr-list-view.js';
@@ -28,7 +26,7 @@
import {ListViewBehavior} from '../../../behaviors/gr-list-view-behavior/gr-list-view-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDocumentationSearch extends mixinBehaviors( [
ListViewBehavior,
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
index 09f4abf..9acfd72 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-default-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrDefaultEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
index 7ca849f..d3a09fe 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-button/gr-button.js';
@@ -35,7 +33,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrEditControls extends mixinBehaviors( [
PatchSetBehavior,
@@ -229,7 +227,7 @@
_handleDeleteConfirm(e) {
// Get the dialog before the api call as the event will change during bubbling
- // which will make Polymer.dom(e).path an emtpy array in polymer 2
+ // which will make Polymer.dom(e).path an empty array in polymer 2
const dialog = this._getDialogFromEvent(e);
this.$.restAPI.deleteFileInChangeEdit(this.change._number, this._path)
.then(res => {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
index 8a24e23..b144bad 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-dropdown/gr-dropdown.js';
import '../../../styles/shared-styles.js';
@@ -25,7 +23,7 @@
import {htmlTemplate} from './gr-edit-file-controls_html.js';
import {GrEditConstants} from '../gr-edit-constants.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrEditFileControls extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
index d2ffa56..886908a 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
import '../../plugins/gr-endpoint-param/gr-endpoint-param.js';
import '../../shared/gr-button/gr-button.js';
@@ -43,7 +41,7 @@
const STORAGE_DEBOUNCE_INTERVAL_MS = 100;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrEditorView extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/gr-app-element.js b/polygerrit-ui/app/elements/gr-app-element.js
index 53c1e54..9c2c6ed 100644
--- a/polygerrit-ui/app/elements/gr-app-element.js
+++ b/polygerrit-ui/app/elements/gr-app-element.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../scripts/bundled-polymer.js';
import '../styles/shared-styles.js';
import '../styles/themes/app-theme.js';
import './admin/gr-admin-view/gr-admin-view.js';
@@ -25,7 +24,6 @@
import './core/gr-error-manager/gr-error-manager.js';
import './core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js';
import './core/gr-main-header/gr-main-header.js';
-import './core/gr-reporting/gr-reporting.js';
import './core/gr-router/gr-router.js';
import './core/gr-smart-search/gr-smart-search.js';
import './diff/gr-diff-view/gr-diff-view.js';
@@ -48,9 +46,10 @@
import {BaseUrlBehavior} from '../behaviors/base-url-behavior/base-url-behavior.js';
import {KeyboardShortcutBehavior} from '../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {GerritNav} from './core/gr-navigation/gr-navigation.js';
+import {appContext} from '../services/app-context.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAppElement extends mixinBehaviors( [
BaseUrlBehavior,
@@ -156,6 +155,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -176,11 +180,13 @@
ready() {
super.ready();
this._updateLoginUrl();
- this.$.reporting.appStarted();
+ this.reporting.appStarted();
this.$.router.start();
this.$.restAPI.getAccount().then(account => {
this._account = account;
+ const role = account ? 'user' : 'guest';
+ this.reporting.reportLifeCycle(`Started as ${role}`);
});
this.$.restAPI.getConfig().then(config => {
this._serverConfig = config;
@@ -411,7 +417,7 @@
if (e.ctrlKey) key = 'ctrl+' + key;
if (e.metaKey) key = 'meta+' + key;
if (e.altKey) key = 'alt+' + key;
- this.$.reporting.reportInteraction('shortcut-triggered', {
+ this.reporting.reportInteraction('shortcut-triggered', {
key,
from: event.path && event.path[0]
&& event.path[0].nodeName || 'unknown',
@@ -461,7 +467,7 @@
const baseUrl = this.getBaseUrl();
if (baseUrl) {
// Strip the canonical path from the path since needing canonical in
- // the path is uneeded and breaks the url.
+ // the path is unneeded and breaks the url.
this._loginUrl = baseUrl + '/login/' + encodeURIComponent(
'/' + window.location.pathname.substring(baseUrl.length) +
window.location.search +
@@ -562,7 +568,7 @@
* that would create a cyclic dependency.
*/
_handleRpcLog(e) {
- this.$.reporting.reportRpcTiming(e.detail.anonymizedUrl,
+ this.reporting.reportRpcTiming(e.detail.anonymizedUrl,
e.detail.elapsed);
}
diff --git a/polygerrit-ui/app/elements/gr-app-element_html.js b/polygerrit-ui/app/elements/gr-app-element_html.js
index 2ee48c1..ad47d52 100644
--- a/polygerrit-ui/app/elements/gr-app-element_html.js
+++ b/polygerrit-ui/app/elements/gr-app-element_html.js
@@ -219,7 +219,6 @@
login-url="[[_loginUrl]]"
></gr-error-manager>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
- <gr-reporting id="reporting"></gr-reporting>
<gr-router id="router"></gr-router>
<gr-plugin-host id="plugins" config="[[_serverConfig]]"> </gr-plugin-host>
<gr-lib-loader id="libLoader"></gr-lib-loader>
diff --git a/polygerrit-ui/app/elements/gr-app-global-var-init.js b/polygerrit-ui/app/elements/gr-app-global-var-init.js
index f0a9131..2c166f5 100644
--- a/polygerrit-ui/app/elements/gr-app-global-var-init.js
+++ b/polygerrit-ui/app/elements/gr-app-global-var-init.js
@@ -48,7 +48,6 @@
import {GrCountStringFormatter} from './shared/gr-count-string-formatter/gr-count-string-formatter.js';
import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider.js';
import {util} from '../scripts/util.js';
-import moment from 'moment/src/moment.js';
import page from 'page/page.mjs';
import {Auth} from './shared/gr-rest-api-interface/gr-auth.js';
import {EventEmitter} from './shared/gr-event-interface/gr-event-interface.js';
@@ -103,7 +102,6 @@
window.GrCountStringFormatter = GrCountStringFormatter;
window.GrReviewerSuggestionsProvider = GrReviewerSuggestionsProvider;
window.util = util;
- window.moment = moment;
window.page = page;
window.Auth = Auth;
window.EventEmitter = EventEmitter;
diff --git a/polygerrit-ui/app/elements/gr-app-init.js b/polygerrit-ui/app/elements/gr-app-init.js
index 7caec6d..780e64a 100644
--- a/polygerrit-ui/app/elements/gr-app-init.js
+++ b/polygerrit-ui/app/elements/gr-app-init.js
@@ -15,6 +15,8 @@
* limitations under the License.
*/
import {initAppContext} from '../services/app-context-init.js';
+import {initVisibilityReporter, initPerformanceReporter, initErrorReporter} from '../services/gr-reporting/gr-reporting.js';
+import {appContext} from '../services/app-context.js';
if (!window.Polymer) {
window.Polymer = {
@@ -24,4 +26,7 @@
}
window.Gerrit = window.Gerrit || {};
-initAppContext();
\ No newline at end of file
+initAppContext();
+initVisibilityReporter(appContext);
+initPerformanceReporter(appContext);
+initErrorReporter(appContext);
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index c9910d3..410539c 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -15,13 +15,9 @@
* limitations under the License.
*/
-/*
- FIXME(polymer-modulizer): the above comments were extracted
- from HTML and may be out of place here. Review them and
- then delete this comment!
-*/
import './gr-app-init.js';
import './font-roboto-local-loader.js';
+// Sets up global Polymer variable, because plugins requires it.
import '../scripts/bundled-polymer.js';
/**
@@ -36,7 +32,6 @@
import 'polymer-resin/standalone/polymer-resin.js';
import {initGlobalVariables} from './gr-app-global-var-init.js';
import './gr-app-element.js';
-import './change-list/gr-embed-dashboard/gr-embed-dashboard.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
@@ -50,7 +45,7 @@
safeTypesBridge: SafeTypes.safeTypesBridge,
});
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrApp extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 6a13789..6322518 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -34,6 +34,7 @@
<script type="module">
import '../test/common-test-setup.js';
import './gr-app.js';
+import {appContext} from '../services/app-context.js';
import {GerritNav} from './core/gr-navigation/gr-navigation.js';
suite('gr-app tests', () => {
@@ -42,9 +43,7 @@
setup(done => {
sandbox = sinon.sandbox.create();
- stub('gr-reporting', {
- appStarted: sandbox.stub(),
- });
+ sandbox.stub(appContext.reportingService, 'appStarted');
stub('gr-account-dropdown', {
_getTopContent: sinon.stub(),
});
@@ -80,12 +79,12 @@
const appElement = () => element.$['app-element'];
test('reporting', () => {
- assert.isTrue(appElement().$.reporting.appStarted.calledOnce);
+ assert.isTrue(appElement().reporting.appStarted.calledOnce);
});
test('reporting called before router start', () => {
const element = appElement();
- const appStartedStub = element.$.reporting.appStarted;
+ const appStartedStub = element.reporting.appStarted;
const routerStartStub = element.$.router.start;
sinon.assert.callOrder(appStartedStub, routerStartStub);
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
index d5ebb65..52c4f4e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="gr-attribute-helper">
diff --git a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.js b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.js
index 8be50b1..ea60dc6 100644
--- a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="gr-change-metadata-api">
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
index 5ef9dbf..41d5fd5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
const $_documentContainer = document.createElement('template');
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
index 62057a1..9bfb7da 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
import {importHref} from '../../../scripts/import-href.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -28,7 +26,7 @@
const INIT_PROPERTIES_TIMEOUT_MS = 10000;
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrEndpointDecorator extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
index 9574391..82402c0 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
@@ -14,13 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrEndpointParam extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
index 63d40fc..da85b9e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="gr-event-helper">
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
index 68b1494..f27053d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
import {importHref} from '../../../scripts/import-href.js';
import {updateStyles} from '@polymer/polymer/lib/mixins/element-mixin.js';
@@ -26,7 +24,7 @@
import {pluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrExternalStyle extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
index d1b2106..1833efa 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrPluginHost extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
index db44cea..eaecd29 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../shared/gr-overlay/gr-overlay.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -25,7 +23,7 @@
(function(window) {
'use strict';
- /** @extends Polymer.Element */
+ /** @extends PolymerElement */
class GrPluginPopup extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
index 3363d72..738b276 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import './gr-plugin-popup.js';
import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
const $_documentContainer = document.createElement('template');
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.js b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.js
index f9a2bdf..752570f 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.js
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../admin/gr-repo-command/gr-repo-command.js';
import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
index 36d822c..445356d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import './gr-plugin-repo-command.js';
const $_documentContainer = document.createElement('template');
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
index 4fb971f..35396cf 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../settings/gr-settings-view/gr-settings-item.js';
import '../../settings/gr-settings-view/gr-settings-menu-item.js';
const $_documentContainer = document.createElement('template');
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
index 3da60db..8a1b601 100644
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {useShadow} from '@polymer/polymer/lib/utils/settings.js';
let styleObjectCount = 0;
@@ -34,7 +35,7 @@
* @return {string} Appropriate class name for the element is returned
*/
GrStyleObject.prototype.getClassName = function(element) {
- let rootNode = Polymer.Settings.useShadow
+ let rootNode = useShadow
? element.getRootNode() : document.body;
if (rootNode === document) {
rootNode = document.head;
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.js b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.js
index 411a7c8..ae8b8ab 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.js
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
Polymer({
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
index c987af3..be427ec 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import './gr-custom-plugin-header.js';
const $_documentContainer = document.createElement('template');
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
index 7e312d3..14b6cfe 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-input/iron-input.js';
import '../../shared/gr-avatar/gr-avatar.js';
import '../../shared/gr-date-formatter/gr-date-formatter.js';
@@ -27,7 +26,7 @@
import {htmlTemplate} from './gr-account-info_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountInfo extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
index 390baf6..0a84f56c 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -27,7 +26,7 @@
import {BaseUrlBehavior} from '../../../behaviors/base-url-behavior/base-url-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAgreementsList extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
index 61e8e93..2051947 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-date-formatter/gr-date-formatter.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -29,7 +28,7 @@
import {ChangeTableBehavior} from '../../../behaviors/gr-change-table-behavior/gr-change-table-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrChangeTableEditor extends mixinBehaviors( [
ChangeTableBehavior,
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
index 79d1390..27532b4 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
@@ -125,7 +125,7 @@
columns.filter(c => c !== 'Assignee'));
});
- test('_handleCheckboxContainerClick relayes taps to checkboxes', () => {
+ test('_handleCheckboxContainerClick relays taps to checkboxes', () => {
sandbox.stub(element, '_handleNumberCheckboxClick');
sandbox.stub(element, '_handleTargetClick');
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
index 957eb48..8359f96 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
@@ -16,7 +16,6 @@
*/
import '@polymer/iron-input/iron-input.js';
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -29,7 +28,7 @@
import {BaseUrlBehavior} from '../../../behaviors/base-url-behavior/base-url-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrClaView extends mixinBehaviors( [
BaseUrlBehavior,
@@ -112,7 +111,7 @@
return this.$.restAPI.saveAccountAgreement({name}).then(res => {
let message = 'Agreement failed to be submitted, please try again';
if (res.status === 200) {
- message = 'Agreement has been successfully submited.';
+ message = 'Agreement has been successfully submitted.';
}
this._createToast(message);
this.loadData();
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
index 2a7ac06..6973292 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../../styles/shared-styles.js';
@@ -26,7 +24,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-edit-preferences_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrEditPreferences extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
index fc97079..0cc5c2c 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -26,7 +24,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-email-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrEmailEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
index 90631c7..6c6ad01 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -29,7 +27,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-gpg-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrGpgEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
index 1cc1369..429a7c7 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../../styles/gr-form-styles.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
@@ -25,7 +23,7 @@
import {htmlTemplate} from './gr-group-list_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrGroupList extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
index 02657f8..164bdee 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-form-styles.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-copy-clipboard/gr-copy-clipboard.js';
@@ -27,7 +25,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-http-password_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrHttpPassword extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
index 74c5eed..d0d30ea 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../../../styles/gr-form-styles.js';
import '../../admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js';
@@ -35,7 +33,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrIdentities extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
index 42982fd..b68915a 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../shared/gr-button/gr-button.js';
import '../../shared/gr-date-formatter/gr-date-formatter.js';
@@ -28,7 +26,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-menu-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrMenuEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
index 6635de2..1da513b 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/gr-form-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -27,7 +25,7 @@
import {htmlTemplate} from './gr-registration-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRegistrationDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
index 3884a15..2455cec 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
@@ -14,13 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-settings-item_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrSettingsItem extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
index 5b11516..4d839f8 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-page-nav-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-settings-menu-item_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrSettingsMenuItem extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
index c2f97ca..95f7a2c 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import '../../../styles/gr-form-styles.js';
@@ -78,7 +76,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrSettingsView extends mixinBehaviors( [
DocsUrlBehavior,
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
index 814eb7a..d869128 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/gr-form-styles.js';
import '../../shared/gr-button/gr-button.js';
@@ -29,7 +27,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-ssh-editor_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrSshEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
index b8960e8..2af1bc7 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../shared/gr-autocomplete/gr-autocomplete.js';
import '../../shared/gr-button/gr-button.js';
@@ -36,7 +34,7 @@
{name: 'Abandons', key: 'notify_abandoned_changes'},
];
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrWatchedProjectsEditor extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
index 6ceee26..c74a396 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-account-link/gr-account-link.js';
import '../gr-button/gr-button.js';
import '../gr-icons/gr-icons.js';
@@ -27,7 +25,7 @@
import {htmlTemplate} from './gr-account-chip_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountChip extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.js b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.js
index c991a37..807aa81 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../gr-autocomplete/gr-autocomplete.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
@@ -28,7 +26,7 @@
* gr-account-entry is an element for entering account
* and/or group with autocomplete support.
*
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountEntry extends GestureEventListeners(
LegacyElementMixin(
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
index 110d884..8c2b7da 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
import '../gr-avatar/gr-avatar.js';
@@ -29,7 +27,7 @@
import {DisplayNameBehavior} from '../../../behaviors/gr-display-name-behavior/gr-display-name-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountLabel extends mixinBehaviors( [
DisplayNameBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
index 27de4b3..d7dd88d 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../gr-account-label/gr-account-label.js';
import '../../../styles/shared-styles.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -27,7 +26,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountLink extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
index 73ccf7d..abe5206 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-account-chip/gr-account-chip.js';
import '../gr-account-entry/gr-account-entry.js';
import '../../../styles/shared-styles.js';
@@ -24,11 +22,12 @@
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-account-list_html.js';
+import {appContext} from '../../../services/app-context.js';
const VALID_EMAIL_ALERT = 'Please input a valid email.';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAccountList extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
@@ -119,6 +118,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -161,10 +165,12 @@
// Append new account or group to the accounts property. We add our own
// internal properties to the account/group here, so we clone the object
// to avoid cluttering up the shared change object.
+ let itemTypeAdded = 'unknown';
if (item.account) {
const account =
Object.assign({}, item.account, {_pendingAdd: true});
this.push('accounts', account);
+ itemTypeAdded = 'account';
} else if (item.group) {
if (item.confirm) {
this.pendingConfirmation = item;
@@ -173,6 +179,7 @@
const group = Object.assign({}, item.group,
{_pendingAdd: true, _group: true});
this.push('accounts', group);
+ itemTypeAdded = 'group';
} else if (this.allowAnyInput) {
if (!item.includes('@')) {
// Repopulate the input with what the user tried to enter and have
@@ -187,8 +194,11 @@
} else {
const account = {email: item, _pendingAdd: true};
this.push('accounts', account);
+ itemTypeAdded = 'email';
}
}
+
+ this.reporting.reportInteraction(`Add to ${this.id}`, {itemTypeAdded});
this.pendingConfirmation = null;
return true;
}
@@ -256,6 +266,7 @@
}
if (matches) {
this.splice('accounts', i, 1);
+ this.reporting.reportInteraction(`Remove from ${this.id}`);
return;
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
index b3b32606..2efc6e8 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
@@ -491,7 +491,7 @@
sandbox.stub(input, '_updateSuggestions');
sandbox.stub(element, '_computeRemovable').returns(true);
flush(() => {
- // Next line is a workaround for Firefix not moving cursor
+ // Next line is a workaround for Firefox not moving cursor
// on input field update
assert.equal(
element._getNativeInput(input.$.input).selectionStart, 0);
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
index 1ec453e..d3a6fad 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-button/gr-button.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -24,7 +22,7 @@
import {htmlTemplate} from './gr-alert_html.js';
import {getRootElement} from '../../../scripts/rootElement.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrAlert extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
index 46e8829..3cf91fe 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-dropdown/iron-dropdown.js';
import {IronFitBehavior} from '@polymer/iron-fit-behavior/iron-fit-behavior.js';
import '../gr-cursor-manager/gr-cursor-manager.js';
@@ -28,7 +27,7 @@
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAutocompleteDropdown extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.js b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.js
index b31af73..fecaa73 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.js
@@ -95,7 +95,7 @@
id="cursor"
index="{{index}}"
cursor-target-class="selected"
- scroll-behavior="never"
+ scroll-mode="never"
focus-on-move=""
stops="[[_suggestionEls]]"
></gr-cursor-manager>
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index 7f9ed72..e6a809e 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-input/paper-input.js';
import '../gr-autocomplete-dropdown/gr-autocomplete-dropdown.js';
import '../gr-cursor-manager/gr-cursor-manager.js';
@@ -33,7 +31,7 @@
const DEBOUNCE_WAIT_MS = 200;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAutocomplete extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
index 75181b1..1385f6d 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../gr-js-api-interface/gr-js-api-interface.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
@@ -28,7 +26,7 @@
import {pluginLoader} from '../gr-js-api-interface/gr-plugin-loader.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrAvatar extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
index 3169c56..6ef4807 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-button/paper-button.js';
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -27,9 +24,10 @@
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {util} from '../../../scripts/util.js';
+import {appContext} from '../../../services/app-context.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrButton extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -80,6 +78,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -104,7 +107,7 @@
return;
}
- this.$.reporting.reportInteraction('button-click',
+ this.reporting.reportInteraction('button-click',
{path: util.getEventPath(e)});
}
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.js b/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.js
index db3b880..e992ffc 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.js
@@ -39,7 +39,7 @@
Without a copy, the @apply works incorrectly with Polymer 2.
@apply is deprecated and is not recommended to use. It is expected
that @apply will be replaced with the ::part CSS pseudo-element.
- After replacecment copied lines can be removed.
+ After replacement copied lines can be removed.
*/
@apply --layout-inline;
@apply --layout-center-center;
@@ -141,7 +141,7 @@
:host([link]) {
--background-color: transparent;
--margin: 0;
- --padding: 5px 4px;
+ --padding: var(--spacing-s);
}
:host([disabled][link]),
:host([loading][link]) {
@@ -173,5 +173,4 @@
<slot></slot>
<i class="downArrow"></i>
</paper-button>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
index ae627d1..dfc3d75 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
@@ -49,6 +49,8 @@
import '../../../test/common-test-setup.js';
import './gr-button.js';
import {addListener} from '@polymer/polymer/lib/utils/gestures.js';
+import {appContext} from '../../../services/app-context.js';
+
suite('gr-button tests', () => {
let element;
let sandbox;
@@ -190,13 +192,10 @@
});
suite('reporting', () => {
- const reportStub = sinon.stub();
+ let reportStub;
setup(() => {
- stub('gr-reporting', {
- reportInteraction: (...args) => {
- reportStub(...args);
- },
- });
+ reportStub = sandbox.stub(appContext.reportingService,
+ 'reportInteraction');
reportStub.reset();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
index 10e06dd..886f0c1 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-icons/gr-icons.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-change-star_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrChangeStar extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
index b99612e..915d171 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-tooltip-content/gr-tooltip-content.js';
import '../../../styles/shared-styles.js';
@@ -43,7 +41,7 @@
const PRIVATE_TOOLTIP = 'This change is only visible to its owner and ' +
'current reviewers (or anyone with "View Private Changes" permission).';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrChangeStatus extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.js b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.js
index ccfc44c..0e2c8a3 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.js
@@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-storage/gr-storage.js';
import '../gr-comment/gr-comment.js';
@@ -29,14 +26,16 @@
import {htmlTemplate} from './gr-comment-thread_html.js';
import {PathListBehavior} from '../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {appContext} from '../../../services/app-context.js';
+import {SpecialFilePath} from '../../../constants/constants.js';
const UNRESOLVED_EXPAND_COUNT = 5;
const NEWLINE_PATTERN = /\n/g;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrCommentThread extends mixinBehaviors( [
/**
@@ -171,6 +170,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
created() {
super.created();
@@ -223,6 +227,10 @@
null, this.lineNum);
}
+ _isPatchsetLevelComment(path) {
+ return path === SpecialFilePath.PATCHSET_LEVEL_COMMENTS;
+ }
+
_computeDisplayPath(path) {
const lineString = this.lineNum ? `#${this.lineNum}` : '';
return this.computeDisplayPath(path) + lineString;
@@ -304,8 +312,8 @@
_sortedComments(comments) {
return comments.slice().sort((c1, c2) => {
- const c1Date = c1.__date || util.parseDate(c1.updated);
- const c2Date = c2.__date || util.parseDate(c2.updated);
+ const c1Date = c1.__date || parseDate(c1.updated);
+ const c2Date = c2.__date || parseDate(c2.updated);
const dateCompare = c1Date - c2Date;
// Ensure drafts are at the end. There should only be one but in edge
// cases could be more. In the unlikely event two drafts are being
@@ -318,15 +326,13 @@
});
}
- _createReplyComment(parent, content, opt_isEditing,
+ _createReplyComment(content, opt_isEditing,
opt_unresolved) {
- this.$.reporting.recordDraftInteraction();
+ this.reporting.recordDraftInteraction();
const reply = this._newReply(
this._orderedComments[this._orderedComments.length - 1].id,
- parent.line,
content,
- opt_unresolved,
- parent.range);
+ opt_unresolved);
// If there is currently a comment in an editing state, add an attribute
// so that the gr-comment knows not to populate the draft text.
@@ -366,25 +372,23 @@
const msg = comment.message;
quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
}
- this._createReplyComment(comment, quoteStr, true, comment.unresolved);
+ this._createReplyComment(quoteStr, true, comment.unresolved);
}
- _handleCommentReply(e) {
+ _handleCommentReply() {
this._processCommentReply();
}
- _handleCommentQuote(e) {
+ _handleCommentQuote() {
this._processCommentReply(true);
}
- _handleCommentAck(e) {
- const comment = this._lastComment;
- this._createReplyComment(comment, 'Ack', false, false);
+ _handleCommentAck() {
+ this._createReplyComment('Ack', false, false);
}
- _handleCommentDone(e) {
- const comment = this._lastComment;
- this._createReplyComment(comment, 'Done', false, false);
+ _handleCommentDone() {
+ this._createReplyComment('Done', false, false);
}
_handleCommentFix(e) {
@@ -392,7 +396,7 @@
const msg = comment.message;
const quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
const response = quoteStr + 'Please fix.';
- this._createReplyComment(comment, response, false, true);
+ this._createReplyComment(response, false, true);
}
_commentElWithDraftID(id) {
@@ -405,11 +409,9 @@
return null;
}
- _newReply(inReplyTo, opt_lineNum, opt_message, opt_unresolved,
- opt_range) {
- const d = this._newDraft(opt_lineNum);
+ _newReply(inReplyTo, opt_message, opt_unresolved) {
+ const d = this._newDraft();
d.in_reply_to = inReplyTo;
- d.range = opt_range;
if (opt_message != null) {
d.message = opt_message;
}
@@ -428,19 +430,40 @@
__draft: true,
__draftID: Math.random().toString(36),
__date: new Date(),
- path: this.path,
- patchNum: this.patchNum,
- side: this._getSide(this.isOnParent),
- __commentSide: this.commentSide,
};
- if (opt_lineNum) {
- d.line = opt_lineNum;
- }
- if (opt_range) {
- d.range = opt_range;
- }
- if (this.parentIndex) {
- d.parent = this.parentIndex;
+
+ // For replies, always use same meta info as root.
+ if (this.comments && this.comments.length >= 1) {
+ const rootComment = this.comments[0];
+ [
+ 'path',
+ 'patchNum',
+ 'side',
+ '__commentSide',
+ 'line',
+ 'range',
+ 'parent',
+ ].forEach(key => {
+ if (rootComment.hasOwnProperty(key)) {
+ d[key] = rootComment[key];
+ }
+ });
+ } else {
+ // Set meta info for root comment.
+ d.path = this.path;
+ d.patchNum = this.patchNum;
+ d.side = this._getSide(this.isOnParent);
+ d.__commentSide = this.commentSide;
+
+ if (opt_lineNum) {
+ d.line = opt_lineNum;
+ }
+ if (opt_range) {
+ d.range = opt_range;
+ }
+ if (this.parentIndex) {
+ d.parent = this.parentIndex;
+ }
}
return d;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.js b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.js
index fbc18b4..88f0ff6 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.js
@@ -27,12 +27,12 @@
gr-button {
margin-left: var(--spacing-m);
}
- gr-comment:not(:last-of-type) {
+ gr-comment {
border-bottom: 1px solid var(--comment-separator-color);
}
#actions {
margin-left: auto;
- padding: var(--spacing-m);
+ padding: var(--spacing-s) var(--spacing-m);
}
#container {
background-color: var(--comment-background-color);
@@ -55,7 +55,6 @@
background-color: var(--robot-comment-background-color);
}
#commentInfoContainer {
- border-top: 1px dotted var(--border-color);
display: flex;
}
#unresolvedLabel {
@@ -76,11 +75,17 @@
</style>
<template is="dom-if" if="[[showFilePath]]">
<div class="pathInfo">
- <a
- href$="[[_getDiffUrlForComment(projectName, changeNum, path, patchNum)]]"
- >[[_computeDisplayPath(path)]]</a
- >
- <span class="descriptionText">Patchset [[patchNum]]</span>
+ <template is="dom-if" if="[[_isPatchsetLevelComment(path)]]">
+ <span>Patchset Comment</span>
+ <span class="descriptionText">Patchset [[patchNum]]</span>
+ </template>
+ <template is="dom-if" if="[[!_isPatchsetLevelComment(path)]]">
+ <a
+ href$="[[_getDiffUrlForComment(projectName, changeNum, path, patchNum)]]"
+ >[[_computeDisplayPath(path)]]</a
+ >
+ <span class="descriptionText">Patchset [[patchNum]]</span>
+ </template>
</div>
</template>
<div
@@ -148,7 +153,6 @@
</div>
</div>
</div>
- <gr-reporting id="reporting"></gr-reporting>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-storage id="storage"></gr-storage>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
index 244a9ec..eaa6547 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.html
@@ -268,6 +268,8 @@
updated: '2015-12-08 19:48:33.843000000',
path: '/path/to/file.txt',
unresolved: true,
+ patchNum: 3,
+ __commentSide: 'left',
}];
flushAsynchronousOperations();
});
@@ -279,7 +281,7 @@
test('reply', () => {
const commentEl = element.shadowRoot
.querySelector('gr-comment');
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
assert.ok(commentEl);
@@ -297,7 +299,7 @@
test('quote reply', () => {
const commentEl = element.shadowRoot
.querySelector('gr-comment');
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
assert.ok(commentEl);
@@ -313,7 +315,7 @@
});
test('quote reply multiline', () => {
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
element.comments = [{
author: {
@@ -344,7 +346,7 @@
});
test('ack', done => {
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
element.changeNum = '42';
element.patchNum = '1';
@@ -367,7 +369,7 @@
});
test('done', done => {
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
element.changeNum = '42';
element.patchNum = '1';
@@ -440,7 +442,6 @@
element.path = '/path/to/file.txt';
element.push('comments', element._newReply(
element.comments[0].id,
- element.comments[0].line,
element.comments[0].path,
'it’s pronouced jiff, not giff'));
flushAsynchronousOperations();
@@ -634,7 +635,7 @@
});
test('comment in_reply_to is either null or most recent comment', () => {
- element._createReplyComment(element.comments[3], 'dummy', true);
+ element._createReplyComment('dummy', true);
flushAsynchronousOperations();
assert.equal(element._orderedComments.length, 5);
assert.equal(element._orderedComments[4].in_reply_to, 'jacks_reply');
@@ -642,7 +643,7 @@
test('resolvable comments', () => {
assert.isFalse(element.unresolved);
- element._createReplyComment(element.comments[3], 'dummy', true, true);
+ element._createReplyComment('dummy', true, true);
flushAsynchronousOperations();
assert.isTrue(element.unresolved);
});
@@ -705,14 +706,21 @@
assert.equal(element.comments[0].unresolved, true);
});
- test('_newDraft', () => {
- element.commentSide = 'left';
- element.patchNum = 3;
+ test('_newDraft with root', () => {
const draft = element._newDraft();
assert.equal(draft.__commentSide, 'left');
assert.equal(draft.patchNum, 3);
});
+ test('_newDraft with no root', () => {
+ element.comments = [];
+ element.commentSide = 'right';
+ element.patchNum = 2;
+ const draft = element._newDraft();
+ assert.equal(draft.__commentSide, 'right');
+ assert.equal(draft.patchNum, 2);
+ });
+
test('new comment gets created', () => {
element.comments = [];
element.addOrEditDraft(1);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
index ee9df11..153b98d 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.js
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
import '../../plugins/gr-endpoint-param/gr-endpoint-param.js';
import '../gr-button/gr-button.js';
@@ -41,6 +38,7 @@
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
import {getRootElement} from '../../../scripts/rootElement.js';
import {GrDisplayNameUtils} from '../../../scripts/gr-display-name-utils/gr-display-name-utils.js';
+import {appContext} from '../../../services/app-context.js';
const STORAGE_DEBOUNCE_INTERVAL = 400;
const TOAST_DEBOUNCE_INTERVAL = 200;
@@ -69,7 +67,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrComment extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -166,6 +164,7 @@
collapsed: {
type: Boolean,
value: true,
+ reflectToAttribute: true,
observer: '_toggleCollapseClass',
},
/** @type {?} */
@@ -241,6 +240,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
attached() {
super.attached();
@@ -283,7 +287,7 @@
this._showRespectfulTip = true;
const randomIdx = this.getRandomNum(0, RESPECTFUL_REVIEW_TIPS.length);
this._respectfulReviewTip = RESPECTFUL_REVIEW_TIPS[randomIdx];
- this.$.reporting.reportInteraction(
+ this.reporting.reportInteraction(
'respectful-tip-appeared',
{tip: this._respectfulReviewTip}
);
@@ -303,7 +307,7 @@
_dismissRespectfulTip() {
this._respectfulTipDismissed = true;
- this.$.reporting.reportInteraction(
+ this.reporting.reportInteraction(
'respectful-tip-dismissed',
{tip: this._respectfulReviewTip}
);
@@ -312,7 +316,7 @@
}
_onRespectfulReadMoreClick() {
- this.$.reporting.reportInteraction('respectful-read-more-clicked');
+ this.reporting.reportInteraction('respectful-read-more-clicked');
}
get textarea() {
@@ -479,7 +483,10 @@
this.$.container.classList.toggle('editing', editing);
if (this.comment && this.comment.id) {
- this.shadowRoot.querySelector('.cancel').hidden = !editing;
+ const cancelButton = this.shadowRoot.querySelector('.cancel');
+ if (cancelButton) {
+ cancelButton.hidden = !editing;
+ }
}
if (this.comment) {
this.comment.__editing = this.editing;
@@ -583,7 +590,7 @@
e.preventDefault();
this._messageText = this.comment.message;
this.editing = true;
- this.$.reporting.recordDraftInteraction();
+ this.reporting.recordDraftInteraction();
}
_handleSave(e) {
@@ -595,7 +602,7 @@
}
const timingLabel = this.comment.id ?
REPORT_UPDATE_DRAFT : REPORT_CREATE_DRAFT;
- const timer = this.$.reporting.getTimer(timingLabel);
+ const timer = this.reporting.getTimer(timingLabel);
this.set('comment.__editing', false);
return this.save().then(() => { timer.end(); });
}
@@ -643,7 +650,7 @@
_handleDiscard(e) {
e.preventDefault();
- this.$.reporting.recordDraftInteraction();
+ this.reporting.recordDraftInteraction();
if (!this._messageText) {
this._discardDraft();
@@ -658,7 +665,7 @@
_handleConfirmDiscard(e) {
e.preventDefault();
- const timer = this.$.reporting.getTimer(REPORT_DISCARD_DRAFT);
+ const timer = this.reporting.getTimer(REPORT_DISCARD_DRAFT);
this._closeConfirmDiscardOverlay();
return this._discardDraft().then(() => { timer.end(); });
}
@@ -799,7 +806,7 @@
}
_handleToggleResolved() {
- this.$.reporting.recordDraftInteraction();
+ this.reporting.recordDraftInteraction();
this.resolved = !this.resolved;
// Modify payload instead of this.comment, as this.comment is passed from
// the parent by ref.
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.js
index fc79cba..3d27042 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.js
@@ -23,6 +23,9 @@
font-family: var(--font-family);
padding: var(--spacing-m);
}
+ :host([collapsed]) {
+ padding: var(--spacing-s) var(--spacing-m);
+ }
:host([disabled]) {
pointer-events: none;
}
@@ -34,20 +37,17 @@
:host([discarding]) {
display: none;
}
+ .body {
+ padding-top: var(--spacing-m);
+ }
.header {
align-items: center;
cursor: pointer;
display: flex;
- margin: calc(0px - var(--spacing-m)) calc(0px - var(--spacing-m)) 0
- calc(0px - var(--spacing-m));
- padding: var(--spacing-m);
}
.headerLeft > span {
font-weight: var(--font-weight-bold);
}
- .container.collapsed .header {
- margin-bottom: calc(0 - var(--spacing-m));
- }
.headerMiddle {
color: var(--deemphasized-text-color);
flex: 1;
@@ -60,8 +60,7 @@
}
.date {
justify-content: flex-end;
- margin-left: 5px;
- min-width: 4.5em;
+ margin-left: var(--spacing-m);
text-align: right;
white-space: nowrap;
}
@@ -77,6 +76,12 @@
justify-content: flex-end;
padding-top: 0;
}
+ .robotActions {
+ /* Better than the negative margin would be to remove the gr-button
+ * padding, but then we would also need to fix the buttons that are
+ * inserted by plugins. :-/ */
+ margin: 4px 0 -4px;
+ }
.action {
margin-left: var(--spacing-l);
}
@@ -131,16 +136,6 @@
.robotId {
color: var(--deemphasized-text-color);
margin-bottom: var(--spacing-m);
- margin-top: -0.4em;
- }
- .robotIcon {
- margin-right: var(--spacing-xs);
- /* because of the antenna of the robot, it looks off center even when it
- is centered. artificially adjust margin to account for this. */
- margin-top: -4px;
- }
- .runIdInformation {
- margin: var(--spacing-m) 0;
}
.robotRun {
margin-left: var(--spacing-m);
@@ -161,16 +156,18 @@
#container .collapsedContent {
display: none;
}
- #container.collapsed {
- padding-bottom: 3px;
+ #container.collapsed .body {
+ padding-top: 0;
}
#container.collapsed .collapsedContent {
display: block;
overflow: hidden;
- padding-left: 5px;
+ padding-left: var(--spacing-m);
text-overflow: ellipsis;
white-space: nowrap;
}
+ #container.collapsed #deleteBtn,
+ #container.collapsed .date,
#container.collapsed .actions,
#container.collapsed gr-formatted-text,
#container.collapsed gr-textarea,
@@ -192,12 +189,6 @@
flex-direction: column;
width: 100%;
}
- .comment-extra-note {
- color: var(--deemphasized-text-color);
- border: 1px solid var(--deemphasized-text-color);
- border-radius: var(--border-radius);
- padding: 0px var(--spacing-s);
- }
#deleteBtn {
display: none;
--gr-button: {
@@ -270,9 +261,6 @@
</a>
</div>
</div>
- <template is="dom-if" if="[[comment.extraNote]]">
- <span class="comment-extra-note">[[comment.extraNote]]</span>
- </template>
<gr-button
id="deleteBtn"
link=""
@@ -373,33 +361,35 @@
Resolved
</label>
</div>
- <div class="rightActions">
- <gr-button
- link=""
- class="action cancel hideOnPublished"
- on-click="_handleCancel"
- >Cancel</gr-button
- >
- <gr-button
- link=""
- class="action discard hideOnPublished"
- on-click="_handleDiscard"
- >Discard</gr-button
- >
- <gr-button
- link=""
- class="action edit hideOnPublished"
- on-click="_handleEdit"
- >Edit</gr-button
- >
- <gr-button
- link=""
- disabled$="[[_computeSaveDisabled(_messageText, comment, resolved)]]"
- class="action save hideOnPublished"
- on-click="_handleSave"
- >Save</gr-button
- >
- </div>
+ <template is="dom-if" if="[[draft]]">
+ <div class="rightActions">
+ <gr-button
+ link=""
+ class="action cancel hideOnPublished"
+ on-click="_handleCancel"
+ >Cancel</gr-button
+ >
+ <gr-button
+ link=""
+ class="action discard hideOnPublished"
+ on-click="_handleDiscard"
+ >Discard</gr-button
+ >
+ <gr-button
+ link=""
+ class="action edit hideOnPublished"
+ on-click="_handleEdit"
+ >Edit</gr-button
+ >
+ <gr-button
+ link=""
+ disabled$="[[_computeSaveDisabled(_messageText, comment, resolved)]]"
+ class="action save hideOnPublished"
+ on-click="_handleSave"
+ >Save</gr-button
+ >
+ </div>
+ </template>
</div>
<div class="robotActions" hidden$="[[!_showRobotActions]]">
<template is="dom-if" if="[[isRobotComment]]">
@@ -458,5 +448,4 @@
</template>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-storage id="storage"></gr-storage>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
index 56581d4..17c01e9 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.html
@@ -259,14 +259,6 @@
});
});
- test('extra note shown if exists', () => {
- element.comment = {id: 'abc_123', extraNote: 'asd'};
- flushAsynchronousOperations();
- assert.equal(element.shadowRoot
- .querySelector('.comment-extra-note')
- .textContent, 'asd');
- });
-
test('delete comment button for non-admins is hidden', () => {
element._isAdmin = false;
assert.isFalse(element.shadowRoot
@@ -320,7 +312,7 @@
sandbox.stub(element, '_discardDraft')
.returns(Promise.resolve({}));
endStub = sinon.stub();
- getTimerStub = sandbox.stub(element.$.reporting, 'getTimer')
+ getTimerStub = sandbox.stub(element.reporting, 'getTimer')
.returns({end: endStub});
});
@@ -354,17 +346,20 @@
});
test('edit reports interaction', () => {
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
+ element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
assert.isTrue(reportStub.calledOnce);
});
test('discard reports interaction', () => {
- const reportStub = sandbox.stub(element.$.reporting,
+ const reportStub = sandbox.stub(element.reporting,
'recordDraftInteraction');
element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.shadowRoot
.querySelector('.discard'));
assert.isTrue(reportStub.calledOnce);
@@ -435,6 +430,7 @@
.querySelector('.robotActions').hasAttribute('hidden'));
element.draft = true;
+ flushAsynchronousOperations();
assert.isTrue(isVisible(element.shadowRoot
.querySelector('.edit')), 'edit is visible');
assert.isTrue(isVisible(element.shadowRoot
@@ -560,6 +556,8 @@
// When the edit button is pressed, should still see the actions
// and also textarea
+ element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
flushAsynchronousOperations();
@@ -663,6 +661,8 @@
test('draft creation/cancellation', done => {
assert.isFalse(element.editing);
+ element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
assert.isTrue(element.editing);
@@ -795,12 +795,13 @@
const cancelDebounce = sandbox.stub(element, 'cancelDebouncer');
element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
element._messageText = 'good news, everyone!';
element.flushDebouncer('fire-update');
element.flushDebouncer('store');
- assert.equal(dispatchEventStub.lastCall.args[0].type, 'comment-update'),
+ assert.equal(dispatchEventStub.lastCall.args[0].type, 'comment-update');
assert.isTrue(dispatchEventStub.calledTwice);
element._messageText = 'good news, everyone!';
@@ -860,6 +861,7 @@
const saveStub = sandbox.stub(element, 'save').returns(Promise.resolve());
element.showActions = true;
element.draft = true;
+ flushAsynchronousOperations();
MockInteractions.tap(element.$.header);
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
index b0f387b..f9ce12e 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
@@ -14,9 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
-
-import '../../../scripts/bundled-polymer.js';
import '../gr-dialog/gr-dialog.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -25,7 +22,7 @@
import {htmlTemplate} from './gr-confirm-delete-comment-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrConfirmDeleteCommentDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
index 0f6168e..39c149f 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/shared-styles.js';
import '../gr-button/gr-button.js';
@@ -28,7 +26,7 @@
const COPY_TIMEOUT_MS = 1000;
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCopyClipboard extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
index 222109e..647f41b 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
@@ -14,18 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-cursor-manager_html.js';
+import {ScrollMode} from '../../../constants/constants.js';
-const ScrollBehavior = {
- NEVER: 'never',
- KEEP_VISIBLE: 'keep-visible',
-};
-
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrCursorManager extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
@@ -82,9 +77,9 @@
*
* @type {string|undefined}
*/
- scrollBehavior: {
+ scrollMode: {
type: String,
- value: ScrollBehavior.NEVER,
+ value: ScrollMode.NEVER,
},
/**
@@ -214,8 +209,8 @@
setCursor(element, opt_noScroll) {
let behavior;
if (opt_noScroll) {
- behavior = this.scrollBehavior;
- this.scrollBehavior = ScrollBehavior.NEVER;
+ behavior = this.scrollMode;
+ this.scrollMode = ScrollMode.NEVER;
}
this.unsetCursor();
@@ -223,7 +218,7 @@
this._updateIndex();
this._decorateTarget();
- if (opt_noScroll) { this.scrollBehavior = behavior; }
+ if (opt_noScroll) { this.scrollMode = behavior; }
}
unsetCursor() {
@@ -391,7 +386,7 @@
*/
_targetIsVisible(top) {
const dims = this._getWindowDims();
- return this.scrollBehavior === ScrollBehavior.KEEP_VISIBLE &&
+ return this.scrollMode === ScrollMode.KEEP_VISIBLE &&
top > (dims.pageYOffset + this.scrollTopMargin) &&
top < dims.pageYOffset + dims.innerHeight;
}
@@ -403,7 +398,7 @@
}
_scrollToTarget() {
- if (!this.target || this.scrollBehavior === ScrollBehavior.NEVER) {
+ if (!this.target || this.scrollMode === ScrollMode.NEVER) {
return;
}
@@ -415,8 +410,8 @@
if (this._targetIsVisible(top)) {
// Don't scroll if either the bottom is visible or if the position that
- // would get scrolled to is higher up than the current position. this
- // woulld cause less of the target content to be displayed than is
+ // would get scrolled to is higher up than the current position. This
+ // would cause less of the target content to be displayed than is
// already.
if (bottomIsVisible || scrollToValue < dims.scrollY) {
return;
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
similarity index 86%
rename from polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
rename to polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
index 98a7d24..561746a 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
@@ -1,32 +1,25 @@
-<!DOCTYPE html>
-<!--
-@license
-Copyright (C) 2016 The Android Open Source Project
+/**
+ * @license
+ * Copyright (C) 2016 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.
+ */
-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
+import '../../../test/common-test-setup-karma.js';
+import './gr-cursor-manager.js';
+import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-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">
-<meta charset="utf-8">
-<title>gr-cursor-manager</title>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
-
-<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-<script src="/components/wct-browser-legacy/browser.js"></script>
-
-<test-fixture id="basic">
- <template>
+const basicTestFixutre = fixtureFromTemplate(html`
<gr-cursor-manager cursor-target-class="targeted"></gr-cursor-manager>
<ul>
<li>A</li>
@@ -34,12 +27,8 @@
<li>C</li>
<li>D</li>
</ul>
- </template>
-</test-fixture>
+`);
-<script type="module">
-import '../../../test/common-test-setup.js';
-import './gr-cursor-manager.js';
suite('gr-cursor-manager tests', () => {
let sandbox;
let element;
@@ -47,7 +36,7 @@
setup(() => {
sandbox = sinon.sandbox.create();
- const fixtureElements = fixture('basic');
+ const fixtureElements = basicTestFixutre.instantiate();
element = fixtureElements[0];
list = fixtureElements[1];
});
@@ -178,7 +167,7 @@
sandbox.stub(element, '_targetIsVisible', () => false);
const scrollStub = sandbox.stub(window, 'scrollTo');
element.stops = list.querySelectorAll('li');
- element.scrollBehavior = 'keep-visible';
+ element.scrollMode = 'keep-visible';
element.setCursorAtIndex(1, true);
assert.isFalse(scrollStub.called);
@@ -236,7 +225,7 @@
let scrollStub;
setup(() => {
element.stops = list.querySelectorAll('li');
- element.scrollBehavior = 'keep-visible';
+ element.scrollMode = 'keep-visible';
// There is a target which has a targetNext
element.setCursor(list.children[0]);
@@ -300,4 +289,3 @@
});
});
});
-</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
index 6f19587..5335ede 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-rest-api-interface/gr-rest-api-interface.js';
import '../../../styles/shared-styles.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -24,13 +22,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-date-formatter_html.js';
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
-import {util} from '../../../scripts/util.js';
-import moment from 'moment/src/moment.js';
-
-const Duration = {
- HOUR: 1000 * 60 * 60,
- DAY: 1000 * 60 * 60 * 24,
-};
+import {parseDate, fromNow, isValidDate, isWithinDay, isWithinHalfYear, formatDate, utcOffsetString} from '../../../utils/date-util.js';
const TimeFormats = {
TIME_12: 'h:mm A', // 2:14 PM
@@ -63,7 +55,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDateFormatter extends mixinBehaviors( [
TooltipBehavior,
@@ -108,6 +100,10 @@
};
}
+ constructor() {
+ super();
+ }
+
/** @override */
attached() {
super.attached();
@@ -115,7 +111,7 @@
}
_getUtcOffsetString() {
- return ' UTC' + moment().format('Z');
+ return utcOffsetString();
}
_loadPreferences() {
@@ -192,50 +188,28 @@
return this.$.restAPI.getPreferences();
}
- /**
- * Return true if date is within 24 hours and on the same day.
- */
- _isWithinDay(now, date) {
- const diff = -date.diff(now);
- return diff < Duration.DAY && date.day() === now.getDay();
- }
-
- /**
- * Returns true if date is from one to six months.
- */
- _isWithinHalfYear(now, date) {
- const diff = -date.diff(now);
- return (date.day() !== now.getDay() || diff >= Duration.DAY) &&
- diff < 180 * Duration.DAY;
- }
-
_computeDateStr(
dateStr, timeFormat, dateFormat, relative, showDateAndTime
) {
if (!dateStr || !timeFormat || !dateFormat) { return ''; }
- const date = moment(util.parseDate(dateStr));
- if (!date.isValid()) { return ''; }
+ const date = parseDate(dateStr);
+ if (!isValidDate(date)) { return ''; }
if (relative) {
- const dateFromNow = date.fromNow();
- if (dateFromNow === 'a few seconds ago') {
- return 'just now';
- } else {
- return dateFromNow;
- }
+ return fromNow(date);
}
const now = new Date();
let format = dateFormat.full;
- if (this._isWithinDay(now, date)) {
+ if (isWithinDay(now, date)) {
format = timeFormat;
} else {
- if (this._isWithinHalfYear(now, date)) {
+ if (isWithinHalfYear(now, date)) {
format = dateFormat.short;
}
if (this.showDateAndTime) {
format = `${format} ${timeFormat}`;
}
}
- return date.format(format);
+ return formatDate(date, format);
}
_timeToSecondsFormat(timeFormat) {
@@ -255,11 +229,11 @@
}
if (!dateStr) { return ''; }
- const date = moment(util.parseDate(dateStr));
- if (!date.isValid()) { return ''; }
+ const date = parseDate(dateStr);
+ if (!isValidDate(date)) { return ''; }
let format = dateFormat.full + ', ';
format += this._timeToSecondsFormat(timeFormat);
- return date.format(format) + this._getUtcOffsetString();
+ return formatDate(date, format) + this._getUtcOffsetString();
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
index 7169ef27..589a157 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
@@ -34,7 +34,7 @@
<script type="module">
import '../../../test/common-test-setup.js';
import './gr-date-formatter.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
suite('gr-date-formatter tests', () => {
let element;
let sandbox;
@@ -51,7 +51,7 @@
* Parse server-formatter date and normalize into current timezone.
*/
function normalizedDate(dateStr) {
- const d = util.parseDate(dateStr);
+ const d = parseDate(dateStr);
d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
return d;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.js b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.js
index db64661..2292ae7 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.js
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-button/gr-button.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -24,7 +22,7 @@
import {htmlTemplate} from './gr-dialog_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.js
index 00f9078..1d00941 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '../../../styles/shared-styles.js';
import '../gr-button/gr-button.js';
@@ -26,7 +24,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-diff-preferences_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrDiffPreferences extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
index fcc09c4..7b92e3d 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/paper-tabs/paper-tabs.js';
import '../gr-shell-command/gr-shell-command.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
@@ -28,7 +26,7 @@
import {RESTClientBehavior} from '../../../behaviors/rest-client-behavior/rest-client-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDownloadCommands extends mixinBehaviors( [
RESTClientBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
index 6b250de..f84ef4a 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-dropdown/iron-dropdown.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-listbox/paper-listbox.js';
@@ -56,7 +54,7 @@
*/
Defs.item;
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrDropdownList extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
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 12a2025..8e7ea87 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-dropdown/iron-dropdown.js';
import '../gr-button/gr-button.js';
import '../gr-cursor-manager/gr-cursor-manager.js';
@@ -35,7 +33,7 @@
const REL_EXTERNAL = 'external';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrDropdown extends mixinBehaviors( [
BaseUrlBehavior,
@@ -184,7 +182,7 @@
}
/**
- * Hanlde a click on the button to open the dropdown.
+ * Handle a click on the button to open the dropdown.
*
* @param {!Event} e
*/
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.js
index d0b0d09..6617a0e 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.js
@@ -161,7 +161,7 @@
<gr-cursor-manager
id="cursor"
cursor-target-class="selected"
- scroll-behavior="never"
+ scroll-mode="never"
focus-on-move=""
stops="[[_listElements]]"
></gr-cursor-manager>
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
index 804eb16..b2bcda9 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/shared-styles.js';
import '../gr-storage/gr-storage.js';
@@ -29,7 +27,7 @@
const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrEditableContent extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
index 8669f03..6c3c72f 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {IronOverlayBehaviorImpl} from '@polymer/iron-overlay-behavior/iron-overlay-behavior.js';
import '@polymer/iron-dropdown/iron-dropdown.js';
import '@polymer/paper-input/paper-input.js';
@@ -33,7 +31,7 @@
const AWAIT_STEP = 5;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrEditableLabel extends mixinBehaviors( [
KeyboardShortcutBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
index 5673194..1d1bce8 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
@@ -188,7 +188,7 @@
element.async(() => {
assert.isFalse(editedStub.called);
- // Text changes sould be discarded.
+ // Text changes should be discarded.
assert.equal(input.value, 'value text');
assert.isFalse(element.editing);
done();
@@ -214,7 +214,7 @@
element.async(() => {
assert.isFalse(editedStub.called);
- // Text changes sould be discarded.
+ // Text changes should be discarded.
assert.equal(input.value, 'value text');
assert.isFalse(element.editing);
done();
diff --git a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js
index 0d19f00..bc79737 100644
--- a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js
+++ b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-fixed-panel_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrFixedPanel extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
index 139e09c..039b95d 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-linked-text/gr-linked-text.js';
import '../../../styles/shared-styles.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -28,7 +26,7 @@
const QUOTE_MARKER_PATTERN = /\n\s?>\s/g;
const CODE_MARKER_PATTERN = /^(`{1,3})([^`]+?)\1$/;
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrFormattedText extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
@@ -91,7 +89,7 @@
/**
* Given a source string, parse into an array of block objects. Each block
- * has a `type` property which takes any of the follwoing values.
+ * has a `type` property which takes any of the following values.
* * 'paragraph'
* * 'quote' (Block quote.)
* * 'pre' (Pre-formatted text.)
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
index 0bc9cb7..49aff7e 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
@@ -26,7 +25,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-hovercard-account_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrHovercardAccount extends GestureEventListeners(
hovercardBehaviorMixin(LegacyElementMixin(
PolymerElement))) {
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.js b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.js
index 8d14ff4..9c8788b 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.js
@@ -64,33 +64,35 @@
}
</style>
<div id="container" role="tooltip" tabindex="-1">
- <div class="top">
- <div class="avatar">
- <gr-avatar account="[[account]]" image-size="56"></gr-avatar>
+ <template is="dom-if" if="[[_isShowing]]">
+ <div class="top">
+ <div class="avatar">
+ <gr-avatar account="[[account]]" image-size="56"></gr-avatar>
+ </div>
+ <div class="account">
+ <h3 class="name">[[account.name]]</h3>
+ <div class="email">[[account.email]]</div>
+ </div>
</div>
- <div class="account">
- <h3 class="name">[[account.name]]</h3>
- <div class="email">[[account.email]]</div>
- </div>
- </div>
- <template is="dom-if" if="[[account.status]]">
- <div class="status">
- <span class="title">
- <iron-icon icon="gr-icons:calendar"></iron-icon>
- Status:
- </span>
- <span class="value">[[account.status]]</span>
+ <template is="dom-if" if="[[account.status]]">
+ <div class="status">
+ <span class="title">
+ <iron-icon icon="gr-icons:calendar"></iron-icon>
+ Status:
+ </span>
+ <span class="value">[[account.status]]</span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[voteableText]]">
+ <div class="voteable">
+ <span class="title">Voteable:</span>
+ <span class="value">[[voteableText]]</span>
+ </div>
+ </template>
+ <div class="attention">
+ <iron-icon icon="gr-icons:attention"></iron-icon>
+ <span>It is this user's turn to take action.</span>
</div>
</template>
- <template is="dom-if" if="[[voteableText]]">
- <div class="voteable">
- <span class="title">Voteable:</span>
- <span class="value">[[voteableText]]</span>
- </div>
- </template>
- <div class="attention">
- <iron-icon icon="gr-icons:attention"></iron-icon>
- <span>It is this user's turn to take action.</span>
- </div>
</div>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.html b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.html
index be0f2b2..884e1b6 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.html
@@ -49,6 +49,8 @@
setup(() => {
element = fixture('basic');
element.account = Object.assign({}, ACCOUNT);
+ element.show({});
+ flushAsynchronousOperations();
});
test('account name is shown', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
index 956c68c..1190908 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {getRootElement} from '../../../scripts/rootElement.js';
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.js b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.js
index e77a4c5..e334064 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -24,7 +23,7 @@
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import './gr-hovercard-shared-style.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrHovercard extends GestureEventListeners(
hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
) {
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.js b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.js
index f7b8b63..bcb85e2 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.js
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.js
@@ -98,6 +98,8 @@
<g id="zeroState"><path d="M22 9V7h-2V5c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-2h2v-2h-2v-2h2v-2h-2V9h2zm-4 10H4V5h14v14zM6 13h5v4H6zm6-6h4v3h-4zM6 7h5v5H6zm6 4h4v6h-4z"></path></g>
<!-- This SVG is an adaptation of material.io https://material.io/icons/#label_important-->
<g id="attention"><path d="M5.5 19 l9 0 c.67 0 1.27 -.33 1.63 -.84 L20.5 12 l-4.37 -6.16 c-.36 -.51 -.96 -.84 -1.63 -.84 l-9 0 L9 12 z"></path></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#pets-->
+ <g id="pets"><circle cx="4.5" cy="9.5" r="2.5"/><circle cx="9" cy="5.5" r="2.5"/><circle cx="15" cy="5.5" r="2.5"/><circle cx="19.5" cy="9.5" r="2.5"/><path d="M17.34 14.86c-.87-1.02-1.6-1.89-2.48-2.91-.46-.54-1.05-1.08-1.75-1.32-.11-.04-.22-.07-.33-.09-.25-.04-.52-.04-.78-.04s-.53 0-.79.05c-.11.02-.22.05-.33.09-.7.24-1.28.78-1.75 1.32-.87 1.02-1.6 1.89-2.48 2.91-1.31 1.31-2.92 2.76-2.62 4.79.29 1.02 1.02 2.03 2.33 2.32.73.15 3.06-.44 5.54-.44h.18c2.48 0 4.81.58 5.54.44 1.31-.29 2.04-1.31 2.33-2.32.31-2.04-1.3-3.49-2.61-4.8z"/><path d="M0 0h24v24H0z" fill="none"/></g>
</defs>
</svg>
</iron-iconset-svg>`;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
index 997e08c..a98936f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -46,7 +44,7 @@
};
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrJsApiInterface extends mixinBehaviors( [
PatchSetBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
index 1cdb20f..6f0ade9 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-import '../../core/gr-reporting/gr-reporting.js';
import '../gr-rest-api-interface/gr-rest-api-interface.js';
import './gr-js-api-interface-element.js';
import './gr-public-js-api.js';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
index e3256a1..63555da 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
@@ -14,6 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
+
export function GrPluginActionContext(plugin, action, change, revision) {
this.action = action;
this.plugin = plugin;
@@ -47,14 +49,14 @@
GrPluginActionContext.prototype.msg = function(text) {
const label = document.createElement('gr-label');
- Polymer.dom(label).appendChild(document.createTextNode(text));
+ dom(label).appendChild(document.createTextNode(text));
return label;
};
GrPluginActionContext.prototype.div = function(...els) {
const div = document.createElement('div');
for (const el of els) {
- Polymer.dom(div).appendChild(el);
+ dom(div).appendChild(el);
}
return div;
};
@@ -62,7 +64,7 @@
GrPluginActionContext.prototype.button = function(label, callbacks) {
const onClick = callbacks && callbacks.onclick;
const button = document.createElement('gr-button');
- Polymer.dom(button).appendChild(document.createTextNode(label));
+ dom(button).appendChild(document.createTextNode(label));
if (onClick) {
this.plugin.eventHelper(button).onTap(onClick);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.js
index 2f27304..6c5546e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.js
@@ -1,3 +1,5 @@
+import {appContext} from '../../../services/app-context.js';
+
/**
* @license
* Copyright (C) 2019 The Android Open Source Project
@@ -15,6 +17,7 @@
* limitations under the License.
*/
import './gr-api-utils.js';
+import {importHref} from '../../../scripts/import-href.js';
import {
PLUGIN_LOADING_TIMEOUT_MS,
@@ -85,7 +88,7 @@
_getReporting() {
if (!this._reporting) {
- this._reporting = document.createElement('gr-reporting');
+ this._reporting = appContext.reportingService;
}
return this._reporting;
}
@@ -333,7 +336,7 @@
};
}
- (Polymer.importHref || Polymer.Base.importHref)(
+ importHref(
url, () => {},
onerror,
!sync);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
index c972f53..ea1fcf2 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.html
@@ -99,12 +99,14 @@
});
test('report pluginsLoaded', done => {
- stub('gr-reporting', {
- pluginsLoaded() {
- done();
- },
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
+ pluginsLoadedStub.reset();
+ window.Gerrit._loadPlugins([]);
+ flush(() => {
+ assert.isTrue(pluginsLoadedStub.calledOnce);
+ done();
});
- pluginLoader.loadPlugins([]);
});
test('arePluginsLoaded', done => {
@@ -129,10 +131,8 @@
sandbox.stub(pluginLoader, '_loadJsPlugin', url => {
pluginApi.install(() => void 0, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
const plugins = [
'http://test.com/plugins/foo/static/test.js',
@@ -151,10 +151,6 @@
sandbox.stub(pluginLoader, '_loadJsPlugin', url => {
pluginApi.install(() => void 0, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
const plugins = [
'http://test.com/plugins/foo/static/test.js',
@@ -193,10 +189,8 @@
}, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
pluginLoader.loadPlugins(plugins);
@@ -225,10 +219,8 @@
}, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
pluginLoader.loadPlugins(plugins);
assert.isTrue(
@@ -260,10 +252,8 @@
}, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
pluginLoader.loadPlugins(plugins);
@@ -289,10 +279,8 @@
}, url === plugins[0] ? '' : 'alpha', url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
pluginLoader.loadPlugins(plugins);
@@ -308,10 +296,8 @@
sandbox.stub(pluginLoader, '_loadJsPlugin', url => {
pluginApi.install(() => void 0, undefined, url);
});
- const pluginsLoadedStub = sandbox.stub();
- stub('gr-reporting', {
- pluginsLoaded: (...args) => pluginsLoadedStub(...args),
- });
+ const pluginsLoadedStub = sandbox.stub(pluginLoader._getReporting(),
+ 'pluginsLoaded');
const plugins = [
'http://test.com/plugins/foo/static/test.js',
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js
index 2c5589f..c003712 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/gr-voting-styles.js';
import '../../../styles/shared-styles.js';
import '../gr-account-label/gr-account-label.js';
@@ -31,7 +29,7 @@
import {htmlTemplate} from './gr-label-info_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLabelInfo extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
@@ -131,7 +129,7 @@
/**
* Closure annotation for Polymer.prototype.splice is off.
- * For now, supressing annotations.
+ * For now, suppressing annotations.
*
* @suppress {checkTypes} */
_onDeleteVote(e) {
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
index a340550..94cfaea 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.html
@@ -212,7 +212,7 @@
let score = '0';
assert.equal(element._computeValueTooltip(labelInfo, score), 'Baz');
- // Non-exsistent score.
+ // Non-existent score.
score = '2';
assert.equal(element._computeValueTooltip(labelInfo, score), '');
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.js b/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
index 014e85e..fa1f758 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -24,7 +22,7 @@
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrLabel extends mixinBehaviors( [
TooltipBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.js
index f585347..d17f7d8 100644
--- a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-autocomplete/gr-autocomplete.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-labeled-autocomplete_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLabeledAutocomplete extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
index 9bd8a11..e9cd441 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-js-api-interface/gr-js-api-interface.js';
import {importHref} from '../../../scripts/import-href.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
@@ -27,7 +25,7 @@
const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
const DARK_THEME_PATH = 'styles/themes/dark-theme.html';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLibLoader extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
index b7bfbf3..1b5224f 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -29,7 +27,7 @@
* configured limit, then an ellipsis indicates that the text was truncated
* and a tooltip containing the full text is enabled.
*
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrLimitedText extends mixinBehaviors( [
TooltipBehavior,
@@ -67,7 +65,7 @@
},
/**
- * The maximum number of characters to display in the tooltop.
+ * The maximum number of characters to display in the tooltip.
*/
tooltipLimit: {
type: Number,
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
index 077ca74..46588ef 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../gr-button/gr-button.js';
import '../gr-icons/gr-icons.js';
@@ -26,7 +25,7 @@
import {htmlTemplate} from './gr-linked-chip_html.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrLinkedChip extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
index 6ea4b78..b969d1d 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -26,7 +24,7 @@
import {GrLinkTextParser} from './link-text-parser.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrLinkedText extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
index 7a44c67..595694c 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-input/iron-input.js';
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
@@ -32,7 +30,7 @@
const REQUEST_DEBOUNCE_INTERVAL_MS = 200;
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrListView extends mixinBehaviors( [
BaseUrlBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
index a5a3fb4..5437ca5 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {IronOverlayBehaviorImpl, IronOverlayBehavior} from '@polymer/iron-overlay-behavior/iron-overlay-behavior.js';
import '../../../styles/shared-styles.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
@@ -29,7 +27,7 @@
const BREAKPOINT_FULLSCREEN_OVERLAY = '50em';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrOverlay extends mixinBehaviors( [
IronOverlayBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
index 8366463..f191981 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
@@ -14,14 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-page-nav_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrPageNav extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.js b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.js
index c499f56..9439c08 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.js
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
import '../gr-icons/gr-icons.js';
@@ -32,7 +30,7 @@
const REF_PREFIX = 'refs/heads/';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRepoBranchPicker extends mixinBehaviors( [
URLEncodingBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
index 5fa476f..f919cbb 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
@@ -87,7 +87,7 @@
});
});
- suite('cache and events behaivor', () => {
+ suite('cache and events behavior', () => {
let fakeFetch;
let clock;
setup(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
index 23b8de7..7402e22 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="gr-etag-decorator">
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 b675df7..2d951d4 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
@@ -16,12 +16,6 @@
*/
/* NB: es6-promise Needed for IE11 and fetch polyfill support, see Issue 4308 */
/* NB: Order is important, because of namespaced classes. */
-/*
- FIXME(polymer-modulizer): the above comments were extracted
- from HTML and may be out of place here. Review them and
- then delete this comment!
-*/
-import '../../../scripts/bundled-polymer.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -35,7 +29,7 @@
import {GrEtagDecorator} from './gr-etag-decorator.js';
import {SiteBasedCache, FetchPromisesCache, GrRestApiHelper} from './gr-rest-apis/gr-rest-api-helper.js';
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
import {authService} from './gr-auth.js';
const DiffViewMode = {
@@ -61,7 +55,7 @@
'/revisions/*';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrRestApiInterface extends mixinBehaviors( [
PathListBehavior,
@@ -2081,7 +2075,7 @@
_setRanges(comments) {
comments = comments || [];
comments.sort(
- (a, b) => util.parseDate(a.updated) - util.parseDate(b.updated)
+ (a, b) => parseDate(a.updated) - parseDate(b.updated)
);
for (const comment of comments) {
this._setRange(comments, comment);
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
index 3d1ce05..ed474d8 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
@@ -15,7 +15,8 @@
* limitations under the License.
*/
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
+import {MessageTag} from '../../../constants/constants.js';
/** @constructor */
export function GrReviewerUpdatesParser(change) {
@@ -52,9 +53,7 @@
*/
GrReviewerUpdatesParser.prototype._filterRemovedMessages = function() {
this.result.messages = this.result.messages
- .filter(
- message => message.tag !== 'autogenerated:gerrit:deleteReviewer'
- );
+ .filter(message => message.tag !== MessageTag.TAG_DELETE_REVIEWER);
};
/**
@@ -68,6 +67,7 @@
author: update.updated_by,
date: update.updated,
type: 'REVIEWER_UPDATE',
+ tag: MessageTag.TAG_REVIEWER_UPDATE,
};
};
@@ -106,8 +106,8 @@
if (!this._batch) {
this._batch = this._startBatch(update);
}
- const updateDate = util.parseDate(update.updated).getTime();
- const batchUpdateDate = util.parseDate(this._batch.date).getTime();
+ const updateDate = parseDate(update.updated).getTime();
+ const batchUpdateDate = parseDate(this._batch.date).getTime();
const reviewerId = update.reviewer._account_id.toString();
if (updateDate - batchUpdateDate >
GrReviewerUpdatesParser.REVIEWER_UPDATE_THRESHOLD_MILLIS ||
@@ -206,14 +206,14 @@
const updates = this.result.reviewer_updates;
const messages = this.result.messages;
messages.forEach((message, index) => {
- const messageDate = util.parseDate(message.date).getTime();
+ const messageDate = parseDate(message.date).getTime();
const nextMessageDate = index === messages.length - 1 ? null :
- util.parseDate(messages[index + 1].date).getTime();
+ parseDate(messages[index + 1].date).getTime();
for (const update of updates) {
- const date = util.parseDate(update.date).getTime();
+ const date = parseDate(update.date).getTime();
if (date >= messageDate &&
(!nextMessageDate || date < nextMessageDate)) {
- const timestamp = util.parseDate(update.date).getTime() -
+ const timestamp = parseDate(update.date).getTime() -
GrReviewerUpdatesParser.MESSAGE_REVIEWERS_THRESHOLD_MILLIS;
update.date = new Date(timestamp)
.toISOString()
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
index f2ccfb7..fa54d6b 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
@@ -27,7 +27,7 @@
<script type="module">
import '../../../test/common-test-setup.js';
import {GrReviewerUpdatesParser} from './gr-reviewer-updates-parser.js';
-import {util} from '../../../scripts/util.js';
+import {parseDate} from '../../../utils/date-util.js';
suite('gr-reviewer-updates-parser tests', () => {
let sandbox;
@@ -253,7 +253,7 @@
});
test('_advanceUpdates', () => {
- const T0 = util.parseDate('2017-02-17 19:04:18.000000000').getTime();
+ const T0 = parseDate('2017-02-17 19:04:18.000000000').getTime();
const tplus = delta => new Date(T0 + delta)
.toISOString()
.replace('T', ' ')
@@ -297,8 +297,8 @@
instance = new GrReviewerUpdatesParser(change);
instance._advanceUpdates();
const updates = instance.result.reviewer_updates;
- assert.isBelow(util.parseDate(updates[0].date).getTime(), T0);
- assert.isBelow(util.parseDate(updates[1].date).getTime(), T0);
+ assert.isBelow(parseDate(updates[0].date).getTime(), T0);
+ assert.isBelow(parseDate(updates[1].date).getTime(), T0);
assert.equal(updates[2].date, tplus(100));
assert.equal(updates[3].date, tplus(500));
});
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
index e061e93..c89378c 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
@@ -29,7 +27,7 @@
document.head.appendChild($_documentContainer.content);
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrSelect extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.js b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.js
index 151498c..a5212fc 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.js
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import '../gr-copy-clipboard/gr-copy-clipboard.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -23,7 +21,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-shell-command_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrShellCommand extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
index 8f5c486..90fdcd3 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
@@ -32,7 +30,7 @@
'editablecontent:': DURATION_DAY,
};
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrStorage extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
index 15ab8e4..e98e11d 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
@@ -14,15 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-autocomplete-dropdown/gr-autocomplete-dropdown.js';
import '../gr-cursor-manager/gr-cursor-manager.js';
import '../gr-overlay/gr-overlay.js';
import '@polymer/iron-a11y-keys-behavior/iron-a11y-keys-behavior.js';
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '../../../styles/shared-styles.js';
-import '../../core/gr-reporting/gr-reporting.js';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -30,6 +27,7 @@
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-textarea_html.js';
import {KeyboardShortcutBehavior} from '../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.js';
+import {appContext} from '../../../services/app-context.js';
const MAX_ITEMS_DROPDOWN = 10;
@@ -67,7 +65,7 @@
];
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrTextarea extends mixinBehaviors( [
KeyboardShortcutBehavior,
@@ -139,6 +137,11 @@
};
}
+ constructor() {
+ super();
+ this.reporting = appContext.reportingService;
+ }
+
/** @override */
ready() {
super.ready();
@@ -214,7 +217,7 @@
this.text = this._getText(text);
this.$.textarea.selectionStart = colonIndex + 1;
this.$.textarea.selectionEnd = colonIndex + 1;
- this.$.reporting.reportInteraction('select-emoji', {type: text});
+ this.reporting.reportInteraction('select-emoji', {type: text});
this._resetEmojiDropdown();
}
@@ -302,7 +305,7 @@
_openEmojiDropdown() {
this.$.emojiSuggestions.open();
- this.$.reporting.reportInteraction('open-emoji-dropdown');
+ this.reporting.reportInteraction('open-emoji-dropdown');
}
_formatSuggestions(matchedSuggestions) {
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_html.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_html.js
index 61e530a..8454f62 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_html.js
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_html.js
@@ -90,5 +90,4 @@
value="{{text}}"
on-bind-value-changed="_onValueChanged"
></iron-autogrow-textarea>
- <gr-reporting id="reporting"></gr-reporting>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index c33b2ae..bcf1207 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -53,7 +53,7 @@
setup(() => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
- sandbox.stub(element.$.reporting, 'reportInteraction');
+ sandbox.stub(element.reporting, 'reportInteraction');
});
teardown(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
index 160f50a..502c82e 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../gr-icons/gr-icons.js';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
@@ -25,7 +23,7 @@
import {TooltipBehavior} from '../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js';
/**
- * @extends Polymer.Element
+ * @extends PolymerElement
*/
class GrTooltipContent extends mixinBehaviors( [
TooltipBehavior,
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
index 0cd2d7c..2244cca 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
@@ -14,15 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
import '../../../styles/shared-styles.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-tooltip_html.js';
-/** @extends Polymer.Element */
+/** @extends PolymerElement */
class GrTooltip extends GestureEventListeners(
LegacyElementMixin(
PolymerElement)) {
diff --git a/polygerrit-ui/app/embed/README.md b/polygerrit-ui/app/embed/README.md
index bef098b..8860878 100644
--- a/polygerrit-ui/app/embed/README.md
+++ b/polygerrit-ui/app/embed/README.md
@@ -1,4 +1,4 @@
-This folder contains shared components that can be used independently from Gerrit.
+This folder contains shared components that can be used independently of Gerrit.
### gr-diff
@@ -10,4 +10,4 @@
All supported attributes defined in `polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js`, you can pass them by just assigning them to the `gr-app` element.
-To customize the style of the diff, you can use `css variables`, all supported varibled defined in `polygerrit-ui/app/styles/themes/app-theme.html` and `polygerrit-ui/app/styles/themes/dark-theme.html`.
+To customize the style of the diff, you can use `css variables`, all supported variables defined in `polygerrit-ui/app/styles/themes/app-theme.html` and `polygerrit-ui/app/styles/themes/dark-theme.html`.
diff --git a/polygerrit-ui/app/embed/app-context-init.js b/polygerrit-ui/app/embed/gr-diff-app-context-init.js
similarity index 75%
rename from polygerrit-ui/app/embed/app-context-init.js
rename to polygerrit-ui/app/embed/gr-diff-app-context-init.js
index 55a5866..8a7fb66 100644
--- a/polygerrit-ui/app/embed/app-context-init.js
+++ b/polygerrit-ui/app/embed/gr-diff-app-context-init.js
@@ -16,6 +16,7 @@
*/
import {appContext} from '../services/app-context.js';
+import {grReportingMock} from '../services/gr-reporting/gr-reporting_mock.js';
class MockFlagsService {
isEnabled(experimentId) {
@@ -34,5 +35,13 @@
// This is a temporary solution
// TODO(dmfilippov): find a better solution for gr-diff
export function initDiffAppContext() {
- appContext.flagsService = new MockFlagsService();
+ function setMock(serviceName, setupMock) {
+ Object.defineProperty(appContext, serviceName, {
+ get() {
+ return setupMock;
+ },
+ });
+ }
+ setMock('flagsService', new MockFlagsService);
+ setMock('reportingService', grReportingMock);
}
diff --git a/polygerrit-ui/app/embed/gr-diff-app-context-init_test.html b/polygerrit-ui/app/embed/gr-diff-app-context-init_test.html
new file mode 100644
index 0000000..3aed13f
--- /dev/null
+++ b/polygerrit-ui/app/embed/gr-diff-app-context-init_test.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2020 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+
+<script type="module">
+ import '../test/common-test-setup.js';
+ import {appContext} from '../services/app-context.js';
+ import {initDiffAppContext} from './gr-diff-app-context-init.js';
+ suite('gr diff app context initializer tests', () => {
+ setup(() => {
+ initDiffAppContext();
+ });
+
+ test('all services initialized and are singletons', () => {
+ Object.keys(appContext).forEach(serviceName => {
+ const service = appContext[serviceName];
+ assert.isNotNull(service);
+ const service2 = appContext[serviceName];
+ assert.strictEqual(service, service2);
+ });
+ });
+ });
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/embed/gr-diff.js b/polygerrit-ui/app/embed/gr-diff.js
index a8b7e03..5907842 100644
--- a/polygerrit-ui/app/embed/gr-diff.js
+++ b/polygerrit-ui/app/embed/gr-diff.js
@@ -16,9 +16,16 @@
*/
window.Gerrit = window.Gerrit || {};
+// TODO(dmfilippov): remove bundled-polymer.js imports when the following issue
+// https://github.com/Polymer/polymer-resin/issues/9 is resolved.
+// Because gr-diff.js is a shared component, it shouldn' pollute global
+// variables. If an application wants to use Polymer global variable -
+// the app must assign/import it and do not rely on the Polymer variable
+// exposed by shared gr-diff component.
+import '../scripts/bundled-polymer.js';
import '../elements/diff/gr-diff/gr-diff.js';
import '../elements/diff/gr-diff-cursor/gr-diff-cursor.js';
-import {initDiffAppContext} from './app-context-init.js';
+import {initDiffAppContext} from './gr-diff-app-context-init.js';
import {GrDiffLine} from '../elements/diff/gr-diff/gr-diff-line.js';
import {GrAnnotation} from '../elements/diff/gr-diff-highlight/gr-annotation.js';
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses.ts b/polygerrit-ui/app/node_modules_licenses/licenses.ts
index fe07569..4c259cd 100644
--- a/polygerrit-ui/app/node_modules_licenses/licenses.ts
+++ b/polygerrit-ui/app/node_modules_licenses/licenses.ts
@@ -273,14 +273,6 @@
license: SharedLicenses.IsArray
},
{
- name: "moment",
- license: {
- name: "moment",
- type: LicenseTypes.Mit,
- packageLicenseFile: "LICENSE"
- }
- },
- {
name: "page",
license: SharedLicenses.Page
},
diff --git a/polygerrit-ui/app/package.json b/polygerrit-ui/app/package.json
index 5989493..a9668c3 100644
--- a/polygerrit-ui/app/package.json
+++ b/polygerrit-ui/app/package.json
@@ -26,7 +26,6 @@
"@webcomponents/shadycss": "^1.9.2",
"@webcomponents/webcomponentsjs": "^1.3.3",
"es6-promise": "^3.3.1",
- "moment": "^2.24.0",
"page": "^1.11.5",
"polymer-bridges": "file:../../polymer-bridges/",
"ba-linkify": "file:../../lib/ba-linkify/src/",
diff --git a/polygerrit-ui/app/rules.bzl b/polygerrit-ui/app/rules.bzl
index 9303f2b..bc2830d 100644
--- a/polygerrit-ui/app/rules.bzl
+++ b/polygerrit-ui/app/rules.bzl
@@ -124,13 +124,14 @@
tags = [
"local",
"manual",
+ "wct",
],
)
def wct_suite(name, srcs, split_count):
"""Define test suites for WCT tests.
- All tests files are splited to split_count WCT suites
+ All tests files are split to split_count WCT suites
Args:
name: rule name. The macro create a test suite rule with the name name+"_test"
diff --git a/polygerrit-ui/app/run_test.sh b/polygerrit-ui/app/run_test.sh
index 5f61de7..a5231a1 100755
--- a/polygerrit-ui/app/run_test.sh
+++ b/polygerrit-ui/app/run_test.sh
@@ -14,4 +14,5 @@
--test_env="DISPLAY=${DISPLAY}" \
--test_env="WCT_HEADLESS_MODE=${WCT_HEADLESS_MODE}" \
"$@" \
- //polygerrit-ui/app:wct_test
+ //polygerrit-ui/app:wct_test \
+ //polygerrit-ui:karma_test
diff --git a/polygerrit-ui/app/scripts/bundled-polymer.js b/polygerrit-ui/app/scripts/bundled-polymer.js
index 711d587..780d82a 100644
--- a/polygerrit-ui/app/scripts/bundled-polymer.js
+++ b/polygerrit-ui/app/scripts/bundled-polymer.js
@@ -17,9 +17,9 @@
// This file is a replacement for the
// polymer-bridges/polymer/polymer.html file. The polymer.html file loads
-// other scripts to setup different global variables. Because polygerrit
-// code still uses global variables (like Polymer.importHref and other),
-// we must setup this global variables after conversion to es6 modules.
+// other scripts to setup different global variables. Because plugins
+// expects that Polymer is available we must setup all Polymer global
+// variables
//
// The bundled-polymer.js imports all scripts in the same order as the
// polymer.html does and must be imported in all es6-modules instead
@@ -68,4 +68,4 @@
import 'polymer-bridges/polymer/polymer-legacy_bridge.js';
import {importHref} from './import-href.js';
-Polymer.importHref = importHref;
+window.Polymer.importHref = importHref;
diff --git a/polygerrit-ui/app/scripts/util.js b/polygerrit-ui/app/scripts/util.js
index 46fa1ad..0103bf2 100644
--- a/polygerrit-ui/app/scripts/util.js
+++ b/polygerrit-ui/app/scripts/util.js
@@ -29,14 +29,6 @@
// TODO (dmfilippov): Each function must be exported separately. According to
// the code style guide, a namespacing is not allowed.
export const util = {
- parseDate(dateStr) {
- // Timestamps are given in UTC and have the format
- // "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
- // nanoseconds.
- // Munge the date into an ISO 8061 format and parse that.
- return new Date(dateStr.replace(' ', 'T') + 'Z');
- },
-
getCookie(name) {
const key = name + '=';
const cookies = document.cookie.split(';');
@@ -89,7 +81,7 @@
* Get computed style value.
*
* If ShadyCSS is provided, use ShadyCSS api.
- * If `getComputedStyleValue` is provided on the elment, use it.
+ * If `getComputedStyleValue` is provided on the element, use it.
* Otherwise fallback to native method (in polymer 2).
*
*/
diff --git a/polygerrit-ui/app/services/app-context-init.js b/polygerrit-ui/app/services/app-context-init.js
index 1c32eee..983314e 100644
--- a/polygerrit-ui/app/services/app-context-init.js
+++ b/polygerrit-ui/app/services/app-context-init.js
@@ -16,14 +16,15 @@
*/
import {appContext} from './app-context.js';
import {FlagsService} from './flags.js';
+import {GrReporting} from './gr-reporting/gr-reporting.js';
const initializedServices = new Map();
function getService(serviceName, serviceInit) {
- if (!initializedServices[serviceName]) {
- initializedServices[serviceName] = serviceInit();
+ if (!initializedServices.has(serviceName)) {
+ initializedServices.set(serviceName, serviceInit());
}
- return initializedServices[serviceName];
+ return initializedServices.get(serviceName);
}
/**
@@ -43,6 +44,8 @@
}
addService('flagsService', () => new FlagsService());
+ addService('reportingService',
+ () => new GrReporting(appContext.flagsService));
Object.defineProperties(appContext, registeredServices);
}
diff --git a/polygerrit-ui/app/services/app-context.js b/polygerrit-ui/app/services/app-context.js
index e10ced5..62b396d 100644
--- a/polygerrit-ui/app/services/app-context.js
+++ b/polygerrit-ui/app/services/app-context.js
@@ -23,4 +23,5 @@
*/
export const appContext = {
flagsService: null,
+ reportingService: null,
};
\ No newline at end of file
diff --git a/polygerrit-ui/app/services/flags.js b/polygerrit-ui/app/services/flags.js
index 8f04f4a..64f0115 100644
--- a/polygerrit-ui/app/services/flags.js
+++ b/polygerrit-ui/app/services/flags.js
@@ -16,6 +16,15 @@
*/
/**
+ * @enum
+ * @desc Experiment ids used in Gerrit.
+ */
+export const ExperimentIds = {
+ CLEANER_CHANGELOG: 'UiFeature__cleaner_changelog',
+ PATCHSET_COMMENTS: 'UiFeature__patchset_comments',
+};
+
+/**
* Flags service.
*
* Provides all related methods / properties regarding on feature flags.
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/services/gr-reporting/gr-reporting.js
similarity index 65%
rename from polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
rename to polygerrit-ui/app/services/gr-reporting/gr-reporting.js
index c8b4ff5..42d112e 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.js
@@ -14,49 +14,53 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../scripts/bundled-polymer.js';
-
-import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
-import {appContext} from '../../../services/app-context.js';
// Latency reporting constants.
+
const TIMING = {
TYPE: 'timing-report',
- CATEGORY_UI_LATENCY: 'UI Latency',
- CATEGORY_RPC: 'RPC Timing',
- // Reported events - alphabetize below.
- APP_STARTED: 'App Started',
+ CATEGORY: {
+ UI_LATENCY: 'UI Latency',
+ RPC: 'RPC Timing',
+ },
+ EVENT: {
+ APP_STARTED: 'App Started',
+ },
};
-// Plugin-related reporting constants.
-const PLUGINS = {
+const LIFECYCLE = {
TYPE: 'lifecycle',
- // Reported events - alphabetize below.
- INSTALLED: 'Plugins installed',
+ CATEGORY: {
+ DEFAULT: 'Default',
+ EXTENSION_DETECTED: 'Extension detected',
+ PLUGINS_INSTALLED: 'Plugins installed',
+ },
};
-// Chrome extension-related reporting constants.
-const EXTENSION = {
- TYPE: 'lifecycle',
- // Reported events - alphabetize below.
- DETECTED: 'Extension detected',
+const INTERACTION = {
+ TYPE: 'interaction',
+ CATEGORY: {
+ DEFAULT: 'Default',
+ VISIBILITY: 'Visibility',
+ },
};
-// Navigation reporting constants.
const NAVIGATION = {
TYPE: 'nav-report',
- CATEGORY: 'Location Changed',
- PAGE: 'Page',
+ CATEGORY: {
+ LOCATION_CHANGED: 'Location Changed',
+ },
+ EVENT: {
+ PAGE: 'Page',
+ },
};
const ERROR = {
TYPE: 'error',
- CATEGORY: 'exception',
-};
-
-const ERROR_DIALOG = {
- TYPE: 'error',
- CATEGORY: 'Error Dialog',
+ CATEGORY: {
+ EXCEPTION: 'exception',
+ ERROR_DIALOG: 'Error Dialog',
+ },
};
const TIMER = {
@@ -89,125 +93,158 @@
STARTUP_TIMERS[TIMER.STARTUP_DIFF_VIEW_DISPLAYED] = 0;
STARTUP_TIMERS[TIMER.STARTUP_DIFF_VIEW_LOAD_FULL] = 0;
STARTUP_TIMERS[TIMER.STARTUP_FILE_LIST_DISPLAYED] = 0;
-STARTUP_TIMERS[TIMING.APP_STARTED] = 0;
+STARTUP_TIMERS[TIMING.EVENT.APP_STARTED] = 0;
// WebComponentsReady timer is triggered from gr-router.
STARTUP_TIMERS[TIMER.WEB_COMPONENTS_READY] = 0;
-const INTERACTION_TYPE = 'interaction';
-
const DRAFT_ACTION_TIMER = 'TimeBetweenDraftActions';
const DRAFT_ACTION_TIMER_MAX = 2 * 60 * 1000; // 2 minutes.
-
-let pending = [];
-let slowRpcList = [];
const SLOW_RPC_THRESHOLD = 500;
-// Variables that hold context info in global scope
-let reportRepoName = undefined;
-
-const onError = function(oldOnError, msg, url, line, column, error) {
- if (oldOnError) {
- oldOnError(msg, url, line, column, error);
- }
- if (error) {
- line = line || error.lineNumber;
- column = column || error.columnNumber;
- let shortenedErrorStack = msg;
- if (error.stack) {
- const errorStackLines = error.stack.split('\n');
- shortenedErrorStack = errorStackLines.slice(0,
- Math.min(3, errorStackLines.length)).join('\n');
+export function initErrorReporter(appContext) {
+ const reportingService = appContext.reportingService;
+ const onError = function(oldOnError, msg, url, line, column, error) {
+ if (oldOnError) {
+ oldOnError(msg, url, line, column, error);
}
- msg = shortenedErrorStack || error.toString();
- }
- const payload = {
- url,
- line,
- column,
- error,
- };
- GrReporting.prototype.reporter(ERROR.TYPE, ERROR.CATEGORY, msg, payload);
- return true;
-};
-
-const catchErrors = function(opt_context) {
- const context = opt_context || window;
- context.onerror = onError.bind(null, context.onerror);
- context.addEventListener('unhandledrejection', e => {
- const msg = e.reason.message;
- const payload = {
- error: e.reason,
- };
- GrReporting.prototype.reporter(ERROR.TYPE, ERROR.CATEGORY, msg, payload);
- });
-};
-catchErrors();
-
-// PerformanceObserver interface is a browser API.
-if (window.PerformanceObserver) {
- const supportedEntryTypes = PerformanceObserver.supportedEntryTypes || [];
- // Safari doesn't support longtask yet
- if (supportedEntryTypes.includes('longtask')) {
- const catchLongJsTasks = new PerformanceObserver(list => {
- for (const task of list.getEntries()) {
- // We are interested in longtask longer than 200 ms (default is 50 ms)
- if (task.duration > 200) {
- GrReporting.prototype.reporter(TIMING.TYPE,
- TIMING.CATEGORY_UI_LATENCY, `Task ${task.name}`,
- Math.round(task.duration), {}, false);
- }
+ if (error) {
+ line = line || error.lineNumber;
+ column = column || error.columnNumber;
+ let shortenedErrorStack = msg;
+ if (error.stack) {
+ const errorStackLines = error.stack.split('\n');
+ shortenedErrorStack = errorStackLines.slice(0,
+ Math.min(3, errorStackLines.length)).join('\n');
}
+ msg = shortenedErrorStack || error.toString();
+ }
+ const payload = {
+ url,
+ line,
+ column,
+ error,
+ };
+ reportingService.reporter(ERROR.TYPE, ERROR.CATEGORY.EXCEPTION,
+ msg, payload);
+ return true;
+ };
+
+ const catchErrors = function(opt_context) {
+ const context = opt_context || window;
+ context.onerror = onError.bind(null, context.onerror);
+ context.addEventListener('unhandledrejection', e => {
+ const msg = e.reason.message;
+ const payload = {
+ error: e.reason,
+ };
+ reportingService.reporter(ERROR.TYPE,
+ ERROR.CATEGORY.EXCEPTION, msg, payload);
});
- catchLongJsTasks.observe({entryTypes: ['longtask']});
+ };
+
+ catchErrors();
+
+ // for testing
+ return {catchErrors};
+}
+
+export function initPerformanceReporter(appContext) {
+ const reportingService = appContext.reportingService;
+ // PerformanceObserver interface is a browser API.
+ if (window.PerformanceObserver) {
+ const supportedEntryTypes = PerformanceObserver.supportedEntryTypes || [];
+ // Safari doesn't support longtask yet
+ if (supportedEntryTypes.includes('longtask')) {
+ const catchLongJsTasks = new PerformanceObserver(list => {
+ for (const task of list.getEntries()) {
+ // We are interested in longtask longer than 200 ms (default is 50 ms)
+ if (task.duration > 200) {
+ reportingService.reporter(TIMING.TYPE,
+ TIMING.CATEGORY.UI_LATENCY, `Task ${task.name}`,
+ Math.round(task.duration), {}, false);
+ }
+ }
+ });
+ catchLongJsTasks.observe({entryTypes: ['longtask']});
+ }
}
}
-document.addEventListener('visibilitychange', () => {
- const eventName = `Visibility changed to ${document.visibilityState}`;
- GrReporting.prototype.reporter(INTERACTION_TYPE, undefined, eventName,
- undefined, {}, true);
-});
+export function initVisibilityReporter(appContext) {
+ const reportingService = appContext.reportingService;
+ document.addEventListener('visibilitychange', () => {
+ reportingService.onVisibilityChange();
+ });
+}
-// The Polymer pass of JSCompiler requires this to be reassignable
-// eslint-disable-next-line prefer-const
-let GrReporting = Polymer({
- is: 'gr-reporting',
+// Calculates the time of Gerrit being in a background tab. When Gerrit reports
+// a pageLoad metric it’s attached to its details for latency analysis.
+// It resets on locationChange.
+class HiddenDurationTimer {
+ constructor() {
+ this.reset();
+ }
- properties: {
- category: String,
+ reset() {
+ this.accHiddenDurationMs = 0;
+ this.lastVisibleTimestampMs = 0;
+ }
- _baselines: {
- type: Object,
- value: STARTUP_TIMERS, // Shared across all instances.
- },
+ onVisibilityChange() {
+ if (document.visibilityState === 'hidden') {
+ this.lastVisibleTimestampMs = now();
+ } else if (document.visibilityState === 'visible') {
+ if (this.lastVisibleTimestampMs !== null) {
+ this.accHiddenDurationMs += now() - this.lastVisibleTimestampMs;
+ // Set to null for guarding against two 'visible' events in a row.
+ this.lastVisibleTimestampMs = null;
+ }
+ }
+ }
- _timers: {
- type: Object,
- value: {timeBetweenDraftActions: null}, // Shared across all instances.
- },
- },
+ get hiddenDurationMs() {
+ if (document.visibilityState === 'hidden'
+ && this.lastVisibleTimestampMs !== null) {
+ return this.accHiddenDurationMs + now() - this.lastVisibleTimestampMs;
+ }
+ return this.accHiddenDurationMs;
+ }
+}
+
+export function now() {
+ return Math.round(window.performance.now());
+}
+
+export class GrReporting {
+ constructor(flagsService) {
+ this._flagsService = flagsService;
+ this._baselines = STARTUP_TIMERS;
+ this._timers = {
+ timeBetweenDraftActions: null,
+ };
+ this._reportRepoName = undefined;
+ this._pending = [];
+ this._slowRpcList = [];
+ this.hiddenDurationTimer = new HiddenDurationTimer();
+ }
get performanceTiming() {
return window.performance.timing;
- },
+ }
get slowRpcSnapshot() {
- return slowRpcList.slice();
- },
-
- now() {
- return Math.round(window.performance.now());
- },
+ return (this._slowRpcList || []).slice();
+ }
_arePluginsLoaded() {
return this._baselines &&
!this._baselines.hasOwnProperty(TIMER.PLUGINS_LOADED);
- },
+ }
_isMetricsPluginLoaded() {
return this._arePluginsLoaded() || this._baselines &&
!this._baselines.hasOwnProperty(TIMER.METRICS_PLUGIN_LOADED);
- },
+ }
/**
* Reporter reports events. Events will be queued if metrics plugin is not
@@ -224,24 +261,24 @@
reporter(type, category, eventName, eventValue, eventDetails, opt_noLog) {
const eventInfo = this._createEventInfo(type, category,
eventName, eventValue, eventDetails);
- if (type === ERROR.TYPE && category === ERROR.CATEGORY) {
+ if (type === ERROR.TYPE && category === ERROR.CATEGORY.EXCEPTION) {
console.error(eventValue && eventValue.error || eventName);
}
// We report events immediately when metrics plugin is loaded
- if (this._isMetricsPluginLoaded() && !pending.length) {
+ if (this._isMetricsPluginLoaded() && !this._pending.length) {
this._reportEvent(eventInfo, opt_noLog);
} else {
// We cache until metrics plugin is loaded
- pending.push([eventInfo, opt_noLog]);
+ this._pending.push([eventInfo, opt_noLog]);
if (this._isMetricsPluginLoaded()) {
- pending.forEach(([eventInfo, opt_noLog]) => {
+ this._pending.forEach(([eventInfo, opt_noLog]) => {
this._reportEvent(eventInfo, opt_noLog);
});
- pending = [];
+ this._pending = [];
}
}
- },
+ }
_reportEvent(eventInfo, opt_noLog) {
const {type, value, name} = eventInfo;
@@ -254,7 +291,7 @@
console.log(`Reporting: ${name}`);
}
}
- },
+ }
_createEventInfo(type, category, name, value, eventDetails) {
const eventInfo = {
@@ -262,7 +299,7 @@
category,
name,
value,
- eventStart: this.now(),
+ eventStart: now(),
};
if (typeof(eventDetails) === 'object' &&
@@ -270,8 +307,8 @@
eventInfo.eventDetails = JSON.stringify(eventDetails);
}
- if (reportRepoName) {
- eventInfo.repoName = reportRepoName;
+ if (this._reportRepoName) {
+ eventInfo.repoName = this._reportRepoName;
}
const isInBackgroundTab = document.visibilityState === 'hidden';
@@ -279,21 +316,30 @@
eventInfo.inBackgroundTab = isInBackgroundTab;
}
- const enabledExperiments = appContext.flagsService.enabledExperiments;
- if (enabledExperiments.length) {
- eventInfo.enabledExperiments = JSON.stringify(enabledExperiments);
+ if (this._flagsService.enabledExperiments.length) {
+ eventInfo.enabledExperiments =
+ JSON.stringify(this._flagsService.enabledExperiments);
}
return eventInfo;
- },
+ }
/**
* User-perceived app start time, should be reported when the app is ready.
*/
appStarted() {
- this.timeEnd(TIMING.APP_STARTED);
+ this.timeEnd(TIMING.EVENT.APP_STARTED);
this._reportNavResTimes();
- },
+ }
+
+ onVisibilityChange() {
+ this.hiddenDurationTimer.onVisibilityChange();
+ const eventName = `Visibility changed to ${document.visibilityState}`;
+ this.reporter(LIFECYCLE.TYPE, LIFECYCLE.CATEGORY.VISIBILITY,
+ eventName, undefined, {
+ hiddenDurationMs: this.hiddenDurationTimer.hiddenDurationMs,
+ }, true);
+ }
/**
* Browser's navigation and resource timings
@@ -303,7 +349,7 @@
perfEvents.forEach(
eventName => this._reportPerformanceTiming(eventName)
);
- },
+ }
_reportPerformanceTiming(eventName, eventDetails) {
const eventTiming = this.performanceTiming[eventName];
@@ -311,10 +357,10 @@
const elapsedTime = eventTiming -
this.performanceTiming.navigationStart;
// NavResTime - Navigation and resource timings.
- this.reporter(TIMING.TYPE, TIMING.CATEGORY_UI_LATENCY,
+ this.reporter(TIMING.TYPE, TIMING.CATEGORY.UI_LATENCY,
`NavResTime - ${eventName}`, elapsedTime, eventDetails, true);
}
- },
+ }
beforeLocationChanged() {
for (const prop of Object.keys(this._baselines)) {
@@ -327,15 +373,16 @@
this.time(TIMER.DIFF_VIEW_DISPLAYED);
this.time(TIMER.DIFF_VIEW_LOAD_FULL);
this.time(TIMER.FILE_LIST_DISPLAYED);
- reportRepoName = undefined;
+ this._reportRepoName = undefined;
// reset slow rpc list since here start page loads which report these rpcs
- slowRpcList = [];
- },
+ this._slowRpcList = [];
+ this.hiddenDurationTimer.reset();
+ }
locationChanged(page) {
- this.reporter(
- NAVIGATION.TYPE, NAVIGATION.CATEGORY, NAVIGATION.PAGE, page);
- },
+ this.reporter(NAVIGATION.TYPE, NAVIGATION.CATEGORY.LOCATION_CHANGED,
+ NAVIGATION.EVENT.PAGE, page);
+ }
dashboardDisplayed() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_DASHBOARD_DISPLAYED)) {
@@ -343,7 +390,7 @@
} else {
this.timeEnd(TIMER.DASHBOARD_DISPLAYED, this._pageLoadDetails());
}
- },
+ }
changeDisplayed() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_CHANGE_DISPLAYED)) {
@@ -351,7 +398,7 @@
} else {
this.timeEnd(TIMER.CHANGE_DISPLAYED, this._pageLoadDetails());
}
- },
+ }
changeFullyLoaded() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_CHANGE_LOAD_FULL)) {
@@ -359,7 +406,7 @@
} else {
this.timeEnd(TIMER.CHANGE_LOAD_FULL);
}
- },
+ }
diffViewDisplayed() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_DIFF_VIEW_DISPLAYED)) {
@@ -367,7 +414,7 @@
} else {
this.timeEnd(TIMER.DIFF_VIEW_DISPLAYED, this._pageLoadDetails());
}
- },
+ }
diffViewFullyLoaded() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_DIFF_VIEW_LOAD_FULL)) {
@@ -375,7 +422,7 @@
} else {
this.timeEnd(TIMER.DIFF_VIEW_LOAD_FULL);
}
- },
+ }
diffViewContentDisplayed() {
if (this._baselines.hasOwnProperty(
@@ -384,7 +431,7 @@
} else {
this.timeEnd(TIMER.DIFF_VIEW_CONTENT_DISPLAYED);
}
- },
+ }
fileListDisplayed() {
if (this._baselines.hasOwnProperty(TIMER.STARTUP_FILE_LIST_DISPLAYED)) {
@@ -392,7 +439,7 @@
} else {
this.timeEnd(TIMER.FILE_LIST_DISPLAYED);
}
- },
+ }
_pageLoadDetails() {
const details = {
@@ -419,33 +466,35 @@
toMb(window.performance.memory.usedJSHeapSize);
}
+ details.hiddenDurationMs = this.hiddenDurationTimer.hiddenDurationMs;
return details;
- },
+ }
reportExtension(name) {
- this.reporter(EXTENSION.TYPE, EXTENSION.DETECTED, name);
- },
+ this.reporter(LIFECYCLE.TYPE, LIFECYCLE.CATEGORY.EXTENSION_DETECTED, name);
+ }
pluginLoaded(name) {
if (name.startsWith('metrics-')) {
this.timeEnd(TIMER.METRICS_PLUGIN_LOADED);
}
- },
+ }
pluginsLoaded(pluginsList) {
this.timeEnd(TIMER.PLUGINS_LOADED);
this.reporter(
- PLUGINS.TYPE, PLUGINS.INSTALLED, PLUGINS.INSTALLED, undefined,
+ LIFECYCLE.TYPE, LIFECYCLE.CATEGORY.PLUGINS_INSTALLED,
+ LIFECYCLE.CATEGORY.PLUGINS_INSTALLED, undefined,
{pluginsList: pluginsList || []}, true);
- },
+ }
/**
* Reset named timer.
*/
time(name) {
- this._baselines[name] = this.now();
+ this._baselines[name] = now();
window.performance.mark(`${name}-start`);
- },
+ }
/**
* Finish named timer and report it to server.
@@ -454,7 +503,7 @@
if (!this._baselines.hasOwnProperty(name)) { return; }
const baseTime = this._baselines[name];
delete this._baselines[name];
- this._reportTiming(name, this.now() - baseTime, eventDetails);
+ this._reportTiming(name, now() - baseTime, eventDetails);
// Finalize the interval. Either from a registered start mark or
// the navigation start time (if baseTime is 0).
@@ -465,7 +514,7 @@
// (if undefined).
window.performance.measure(name);
}
- },
+ }
/**
* Reports just line timeEnd, but additionally reports an average given a
@@ -483,9 +532,9 @@
// Guard against division by zero.
if (!denominator) { return; }
- const time = this.now() - baseTime;
+ const time = now() - baseTime;
this._reportTiming(averageName, time / denominator);
- },
+ }
/**
* Send a timing report with an arbitrary time value.
@@ -495,9 +544,9 @@
* @param {Object} eventDetails non sensitive details
*/
_reportTiming(name, time, eventDetails) {
- this.reporter(TIMING.TYPE, TIMING.CATEGORY_UI_LATENCY, name, time,
+ this.reporter(TIMING.TYPE, TIMING.CATEGORY.UI_LATENCY, name, time,
eventDetails);
- },
+ }
/**
* Get a timer object to for reporing a user timing. The start time will be
@@ -517,7 +566,7 @@
// Clear the timer and reset the start time.
reset: () => {
called = false;
- start = this.now();
+ start = now();
return timer;
},
@@ -527,7 +576,7 @@
throw new Error(`Timer for "${name}" already ended.`);
}
called = true;
- const time = this.now() - start;
+ const time = now() - start;
// If a maximum is specified and the time exceeds it, do not report.
if (max && time > max) { return timer; }
@@ -546,7 +595,7 @@
// The timer is initialized to its creation time.
return timer.reset();
- },
+ }
/**
* Log timing information for an RPC.
@@ -555,17 +604,22 @@
* @param {number} elapsed The time elapsed of the RPC.
*/
reportRpcTiming(anonymizedUrl, elapsed) {
- this.reporter(TIMING.TYPE, TIMING.CATEGORY_RPC, 'RPC-' + anonymizedUrl,
+ this.reporter(TIMING.TYPE, TIMING.CATEGORY.RPC, 'RPC-' + anonymizedUrl,
elapsed, {}, true);
if (elapsed >= SLOW_RPC_THRESHOLD) {
- slowRpcList.push({anonymizedUrl, elapsed});
+ this._slowRpcList.push({anonymizedUrl, elapsed});
}
- },
+ }
+
+ reportLifeCycle(eventName, details) {
+ this.reporter(LIFECYCLE.TYPE, LIFECYCLE.CATEGORY.DEFAULT, eventName,
+ undefined, details, true);
+ }
reportInteraction(eventName, details) {
- this.reporter(INTERACTION_TYPE, this.category, eventName, undefined,
- details, true);
- },
+ this.reporter(INTERACTION.TYPE, INTERACTION.CATEGORY.DEFAULT, eventName,
+ undefined, details, true);
+ }
/**
* A draft interaction was started. Update the time-betweeen-draft-actions
@@ -585,19 +639,16 @@
// Mark the time and reinitialize the timer.
timer.end().reset();
- },
+ }
reportErrorDialog(message) {
- this.reporter(ERROR_DIALOG.TYPE, ERROR_DIALOG.CATEGORY,
+ this.reporter(ERROR.TYPE, ERROR.CATEGORY.ERROR_DIALOG,
'ErrorDialog: ' + message, {error: new Error(message)});
- },
+ }
setRepoName(repoName) {
- reportRepoName = repoName;
- },
-});
+ this._reportRepoName = repoName;
+ }
+}
-window.GrReporting = GrReporting;
-// Expose onerror installation so it would be accessible from tests.
-window.GrReporting._catchErrors = catchErrors;
-window.GrReporting.STARTUP_TIMERS = Object.assign({}, STARTUP_TIMERS);
+export const DEFAULT_STARTUP_TIMERS = Object.assign({}, STARTUP_TIMERS);
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.js b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.js
new file mode 100644
index 0000000..1ef2483
--- /dev/null
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.js
@@ -0,0 +1,45 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export const grReportingMock = {
+ appStarted: () => {},
+ beforeLocationChanged: () => {},
+ changeDisplayed: () => {},
+ changeFullyLoaded: () => {},
+ dashboardDisplayed: () => {},
+ diffViewContentDisplayed: () => {},
+ diffViewDisplayed: () => {},
+ diffViewFullyLoaded: () => {},
+ fileListDisplayed: () => {},
+ getTimer: () => {
+ return {end: () => {}};
+ },
+ locationChanged: () => {},
+ onVisibilityChange: () => {},
+ pluginLoaded: () => {},
+ pluginsLoaded: () => {},
+ recordDraftInteraction: () => {},
+ reporter: () => {},
+ reportErrorDialog: () => {},
+ reportExtension: () => {},
+ reportInteraction: () => {},
+ reportLifeCycle: () => {},
+ reportRpcTiming: () => {},
+ setRepoName: () => {},
+ time: () => {},
+ timeEnd: () => {},
+ timeEndWithAverage: () => {},
+};
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock_test.html b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock_test.html
new file mode 100644
index 0000000..e33a214
--- /dev/null
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock_test.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2020 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+
+<script type="module">
+ import '../../test/common-test-setup.js';
+ import {GrReporting} from './gr-reporting.js';
+ import {grReportingMock} from './gr-reporting_mock.js';
+ suite('gr-reporting_mock tests', () => {
+ test('mocks all public methods', () => {
+ const methods = Object.getOwnPropertyNames(GrReporting.prototype)
+ .filter(name => typeof GrReporting.prototype[name] === 'function')
+ .filter(name => !name.startsWith('_') && name !== 'constructor')
+ .sort();
+ const mockMethods = Object.getOwnPropertyNames(grReportingMock)
+ .sort();
+ assert.deepEqual(methods, mockMethods);
+ });
+ });
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.html
new file mode 100644
index 0000000..e309c8c
--- /dev/null
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.html
@@ -0,0 +1,513 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2016 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">
+<meta charset="utf-8">
+<title>gr-reporting</title>
+
+<script src="/node_modules/@webcomponents/webcomponentsjs/custom-services-es5-adapter.js"></script>
+
+<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
+<script src="/components/wct-browser-legacy/browser.js"></script>
+
+<script type="module">
+import '../../test/common-test-setup.js';
+import {GrReporting, DEFAULT_STARTUP_TIMERS, initErrorReporter} from './gr-reporting.js';
+import {appContext} from '../app-context.js';
+suite('gr-reporting tests', () => {
+ let service;
+ let sandbox;
+ let clock;
+ let fakePerformance;
+
+ const NOW_TIME = 100;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ clock = sinon.useFakeTimers(NOW_TIME);
+ service = new GrReporting(appContext.flagsService);
+ service._baselines = Object.assign({}, DEFAULT_STARTUP_TIMERS);
+ sandbox.stub(service, 'reporter');
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ clock.restore();
+ });
+
+ test('appStarted', () => {
+ fakePerformance = {
+ navigationStart: 1,
+ loadEventEnd: 2,
+ };
+ fakePerformance.toJSON = () => fakePerformance;
+ sinon.stub(service, 'performanceTiming',
+ {get() { return fakePerformance; }});
+ sandbox.stub(window.performance, 'now').returns(42);
+ service.appStarted();
+ assert.isTrue(
+ service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'App Started', 42
+ ));
+ assert.isTrue(
+ service.reporter.calledWithExactly(
+ 'timing-report', 'UI Latency', 'NavResTime - loadEventEnd',
+ fakePerformance.loadEventEnd - fakePerformance.navigationStart,
+ undefined, true)
+ );
+ });
+
+ test('WebComponentsReady', () => {
+ sandbox.stub(window.performance, 'now').returns(42);
+ service.timeEnd('WebComponentsReady');
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'WebComponentsReady', 42
+ ));
+ });
+
+ test('beforeLocationChanged', () => {
+ service._baselines['garbage'] = 'monster';
+ sandbox.stub(service, 'time');
+ service.beforeLocationChanged();
+ assert.isTrue(service.time.calledWithExactly('DashboardDisplayed'));
+ assert.isTrue(service.time.calledWithExactly('ChangeDisplayed'));
+ assert.isTrue(service.time.calledWithExactly('ChangeFullyLoaded'));
+ assert.isTrue(service.time.calledWithExactly('DiffViewDisplayed'));
+ assert.isTrue(service.time.calledWithExactly('FileListDisplayed'));
+ assert.isFalse(service._baselines.hasOwnProperty('garbage'));
+ });
+
+ test('changeDisplayed', () => {
+ sandbox.spy(service, 'timeEnd');
+ service.changeDisplayed();
+ assert.isFalse(service.timeEnd.calledWith('ChangeDisplayed'));
+ assert.isTrue(service.timeEnd.calledWith('StartupChangeDisplayed'));
+ service.changeDisplayed();
+ assert.isTrue(service.timeEnd.calledWith('ChangeDisplayed'));
+ });
+
+ test('changeFullyLoaded', () => {
+ sandbox.spy(service, 'timeEnd');
+ service.changeFullyLoaded();
+ assert.isFalse(
+ service.timeEnd.calledWithExactly('ChangeFullyLoaded'));
+ assert.isTrue(
+ service.timeEnd.calledWithExactly('StartupChangeFullyLoaded'));
+ service.changeFullyLoaded();
+ assert.isTrue(service.timeEnd.calledWithExactly('ChangeFullyLoaded'));
+ });
+
+ test('diffViewDisplayed', () => {
+ sandbox.spy(service, 'timeEnd');
+ service.diffViewDisplayed();
+ assert.isFalse(service.timeEnd.calledWith('DiffViewDisplayed'));
+ assert.isTrue(service.timeEnd.calledWith('StartupDiffViewDisplayed'));
+ service.diffViewDisplayed();
+ assert.isTrue(service.timeEnd.calledWith('DiffViewDisplayed'));
+ });
+
+ test('fileListDisplayed', () => {
+ sandbox.spy(service, 'timeEnd');
+ service.fileListDisplayed();
+ assert.isFalse(
+ service.timeEnd.calledWithExactly('FileListDisplayed'));
+ assert.isTrue(
+ service.timeEnd.calledWithExactly('StartupFileListDisplayed'));
+ service.fileListDisplayed();
+ assert.isTrue(service.timeEnd.calledWithExactly('FileListDisplayed'));
+ });
+
+ test('dashboardDisplayed', () => {
+ sandbox.spy(service, 'timeEnd');
+ service.dashboardDisplayed();
+ assert.isFalse(service.timeEnd.calledWith('DashboardDisplayed'));
+ assert.isTrue(service.timeEnd.calledWith('StartupDashboardDisplayed'));
+ service.dashboardDisplayed();
+ assert.isTrue(service.timeEnd.calledWith('DashboardDisplayed'));
+ });
+
+ test('dashboardDisplayed details', () => {
+ sandbox.spy(service, 'timeEnd');
+ sandbox.stub(window, 'performance', {
+ memory: {
+ usedJSHeapSize: 1024 * 1024,
+ },
+ measure: () => {},
+ now: () => { 42; },
+ });
+ service.reportRpcTiming('/changes/*~*/comments', 500);
+ service.dashboardDisplayed();
+ assert.isTrue(
+ service.timeEnd.calledWithExactly('StartupDashboardDisplayed',
+ {rpcList: [
+ {
+ anonymizedUrl: '/changes/*~*/comments',
+ elapsed: 500,
+ },
+ ],
+ screenSize: {
+ width: window.screen.width,
+ height: window.screen.height,
+ },
+ viewport: {
+ width: document.documentElement.clientWidth,
+ height: document.documentElement.clientHeight,
+ },
+ usedJSHeapSizeMb: 1,
+ hiddenDurationMs: 0,
+ }
+ ));
+ });
+
+ suite('hidden duration', () => {
+ let nowStub;
+ let visibilityStateStub;
+ const assertHiddenDurationsMs = hiddenDurationMs => {
+ service.dashboardDisplayed();
+ assert.isTrue(
+ service.timeEnd.calledWithMatch('StartupDashboardDisplayed',
+ {hiddenDurationMs}
+ ));
+ };
+
+ setup(() => {
+ sandbox.spy(service, 'timeEnd');
+ nowStub = sandbox.stub(window.performance, 'now');
+ visibilityStateStub = {
+ value: value => {
+ Object.defineProperty(document, 'visibilityState',
+ {value, configurable: true});
+ },
+ };
+ });
+
+ test('starts in hidden', () => {
+ nowStub.returns(10);
+ visibilityStateStub.value('hidden');
+ service.onVisibilityChange();
+ nowStub.returns(15);
+ visibilityStateStub.value('visible');
+ service.onVisibilityChange();
+ assertHiddenDurationsMs(5);
+ });
+
+ test('full in hidden', () => {
+ nowStub.returns(10);
+ visibilityStateStub.value('hidden');
+ assertHiddenDurationsMs(10);
+ });
+
+ test('full in visible', () => {
+ nowStub.returns(10);
+ visibilityStateStub.value('visible');
+ assertHiddenDurationsMs(0);
+ });
+
+ test('accumulated', () => {
+ nowStub.returns(10);
+ visibilityStateStub.value('hidden');
+ service.onVisibilityChange();
+ nowStub.returns(15);
+ visibilityStateStub.value('visible');
+ service.onVisibilityChange();
+ nowStub.returns(20);
+ visibilityStateStub.value('hidden');
+ service.onVisibilityChange();
+ nowStub.returns(25);
+ assertHiddenDurationsMs(10);
+ });
+
+ test('reset after location change', () => {
+ nowStub.returns(10);
+ visibilityStateStub.value('hidden');
+ assertHiddenDurationsMs(10);
+ visibilityStateStub.value('visible');
+ nowStub.returns(15);
+ service.beforeLocationChanged();
+ service.timeEnd.reset();
+ service.dashboardDisplayed();
+ assert.isTrue(
+ service.timeEnd.calledWithMatch('DashboardDisplayed',
+ {hiddenDurationMs: 0}
+ ));
+ });
+ });
+
+ test('time and timeEnd', () => {
+ const nowStub = sandbox.stub(window.performance, 'now').returns(0);
+ service.time('foo');
+ nowStub.returns(1);
+ service.time('bar');
+ nowStub.returns(2);
+ service.timeEnd('bar');
+ nowStub.returns(3);
+ service.timeEnd('foo');
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'foo', 3
+ ));
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'bar', 1
+ ));
+ });
+
+ test('timer object', () => {
+ const nowStub = sandbox.stub(window.performance, 'now').returns(100);
+ const timer = service.getTimer('foo-bar');
+ nowStub.returns(150);
+ timer.end();
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'foo-bar', 50));
+ });
+
+ test('timer object double call', () => {
+ const timer = service.getTimer('foo-bar');
+ timer.end();
+ assert.isTrue(service.reporter.calledOnce);
+ assert.throws(() => {
+ timer.end();
+ }, 'Timer for "foo-bar" already ended.');
+ });
+
+ test('timer object maximum', () => {
+ const nowStub = sandbox.stub(window.performance, 'now').returns(100);
+ const timer = service.getTimer('foo-bar').withMaximum(100);
+ nowStub.returns(150);
+ timer.end();
+ assert.isTrue(service.reporter.calledOnce);
+
+ timer.reset();
+ nowStub.returns(260);
+ timer.end();
+ assert.isTrue(service.reporter.calledOnce);
+ });
+
+ test('recordDraftInteraction', () => {
+ const key = 'TimeBetweenDraftActions';
+ const nowStub = sandbox.stub(window.performance, 'now').returns(100);
+ const timingStub = sandbox.stub(service, '_reportTiming');
+ service.recordDraftInteraction();
+ assert.isFalse(timingStub.called);
+
+ nowStub.returns(200);
+ service.recordDraftInteraction();
+ assert.isTrue(timingStub.calledOnce);
+ assert.equal(timingStub.lastCall.args[0], key);
+ assert.equal(timingStub.lastCall.args[1], 100);
+
+ nowStub.returns(350);
+ service.recordDraftInteraction();
+ assert.isTrue(timingStub.calledTwice);
+ assert.equal(timingStub.lastCall.args[0], key);
+ assert.equal(timingStub.lastCall.args[1], 150);
+
+ nowStub.returns(370 + 2 * 60 * 1000);
+ service.recordDraftInteraction();
+ assert.isFalse(timingStub.calledThrice);
+ });
+
+ test('timeEndWithAverage', () => {
+ const nowStub = sandbox.stub(window.performance, 'now').returns(0);
+ nowStub.returns(1000);
+ service.time('foo');
+ nowStub.returns(1100);
+ service.timeEndWithAverage('foo', 'bar', 10);
+ assert.isTrue(service.reporter.calledTwice);
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'foo', 100));
+ assert.isTrue(service.reporter.calledWithMatch(
+ 'timing-report', 'UI Latency', 'bar', 10));
+ });
+
+ test('reportExtension', () => {
+ service.reportExtension('foo');
+ assert.isTrue(service.reporter.calledWithExactly(
+ 'lifecycle', 'Extension detected', 'foo'
+ ));
+ });
+
+ test('reportInteraction', () => {
+ service.reporter.restore();
+ sandbox.spy(service, '_reportEvent');
+ service.pluginsLoaded(); // so we don't cache
+ service.reportInteraction('button-click', {name: 'sendReply'});
+ assert.isTrue(service._reportEvent.getCall(2).calledWithMatch(
+ {
+ type: 'interaction',
+ name: 'button-click',
+ eventDetails: JSON.stringify({name: 'sendReply'}),
+ }
+ ));
+ });
+
+ test('report start time', () => {
+ service.reporter.restore();
+ sandbox.stub(window.performance, 'now').returns(42);
+ sandbox.spy(service, '_reportEvent');
+ const dispatchStub = sandbox.spy(document, 'dispatchEvent');
+ service.pluginsLoaded();
+ service.time('timeAction');
+ service.timeEnd('timeAction');
+ assert.isTrue(service._reportEvent.getCall(2).calledWithMatch(
+ {
+ type: 'timing-report',
+ category: 'UI Latency',
+ name: 'timeAction',
+ value: 0,
+ eventStart: 42,
+ }
+ ));
+ assert.equal(dispatchStub.getCall(2).args[0].detail.eventStart, 42);
+ });
+
+ suite('plugins', () => {
+ setup(() => {
+ service.reporter.restore();
+ sandbox.stub(service, '_reportEvent');
+ });
+
+ test('pluginsLoaded reports time', () => {
+ sandbox.stub(window.performance, 'now').returns(42);
+ service.pluginsLoaded();
+ assert.isTrue(service._reportEvent.calledWithMatch(
+ {
+ type: 'timing-report',
+ category: 'UI Latency',
+ name: 'PluginsLoaded',
+ value: 42,
+ }
+ ));
+ });
+
+ test('pluginsLoaded reports plugins', () => {
+ service.pluginsLoaded(['foo', 'bar']);
+ assert.isTrue(service._reportEvent.calledWithMatch(
+ {
+ type: 'lifecycle',
+ category: 'Plugins installed',
+ eventDetails: JSON.stringify({pluginsList: ['foo', 'bar']}),
+ }
+ ));
+ });
+
+ test('caches reports if plugins are not loaded', () => {
+ service.timeEnd('foo');
+ assert.isFalse(service._reportEvent.called);
+ });
+
+ test('reports if plugins are loaded', () => {
+ service.pluginsLoaded();
+ assert.isTrue(service._reportEvent.called);
+ });
+
+ test('reports if metrics plugin xyz is loaded', () => {
+ service.pluginLoaded('metrics-xyz');
+ assert.isTrue(service._reportEvent.called);
+ });
+
+ test('reports cached events preserving order', () => {
+ service.time('foo');
+ service.time('bar');
+ service.timeEnd('foo');
+ service.pluginsLoaded();
+ service.timeEnd('bar');
+ assert.isTrue(service._reportEvent.getCall(0).calledWithMatch(
+ {type: 'timing-report', category: 'UI Latency', name: 'foo'}
+ ));
+ assert.isTrue(service._reportEvent.getCall(1).calledWithMatch(
+ {type: 'timing-report', category: 'UI Latency',
+ name: 'PluginsLoaded'}
+ ));
+ assert.isTrue(service._reportEvent.getCall(2).calledWithMatch(
+ {type: 'lifecycle', category: 'Plugins installed'}
+ ));
+ assert.isTrue(service._reportEvent.getCall(3).calledWithMatch(
+ {type: 'timing-report', category: 'UI Latency', name: 'bar'}
+ ));
+ });
+ });
+
+ test('search', () => {
+ service.locationChanged('_handleSomeRoute');
+ assert.isTrue(service.reporter.calledWithExactly(
+ 'nav-report', 'Location Changed', 'Page', '_handleSomeRoute'));
+ });
+
+ suite('exception logging', () => {
+ let fakeWindow;
+ let reporter;
+
+ const emulateThrow = function(msg, url, line, column, error) {
+ return fakeWindow.onerror(msg, url, line, column, error);
+ };
+
+ setup(() => {
+ reporter = service.reporter;
+ fakeWindow = {
+ handlers: {},
+ addEventListener(type, handler) {
+ this.handlers[type] = handler;
+ },
+ };
+ sandbox.stub(console, 'error');
+ Object.defineProperty(appContext, 'reportingService', {
+ get() {
+ return service;
+ },
+ });
+ const errorReporter = initErrorReporter(appContext);
+ errorReporter.catchErrors(fakeWindow);
+ });
+
+ test('is reported', () => {
+ const error = new Error('bar');
+ error.stack = undefined;
+ emulateThrow('bar', 'http://url', 4, 2, error);
+ assert.isTrue(reporter.calledWith('error', 'exception', 'bar'));
+ const payload = reporter.lastCall.args[3];
+ assert.deepEqual(payload, {
+ url: 'http://url',
+ line: 4,
+ column: 2,
+ error,
+ });
+ });
+
+ test('is reported with 3 lines of stack', () => {
+ const error = new Error('bar');
+ emulateThrow('bar', 'http://url', 4, 2, error);
+ const expectedStack = error.stack.split('\n').slice(0, 3)
+ .join('\n');
+ assert.isTrue(reporter.calledWith('error', 'exception',
+ expectedStack));
+ });
+
+ test('prevent default event handler', () => {
+ assert.isTrue(emulateThrow());
+ });
+
+ test('unhandled rejection', () => {
+ fakeWindow.handlers['unhandledrejection']({
+ reason: {
+ message: 'bar',
+ },
+ });
+ assert.isTrue(reporter.calledWith('error', 'exception', 'bar'));
+ });
+ });
+});
+</script>
diff --git a/polygerrit-ui/app/test/a11y-test-utils.js b/polygerrit-ui/app/test/a11y-test-utils.js
new file mode 100644
index 0000000..a687e07
--- /dev/null
+++ b/polygerrit-ui/app/test/a11y-test-utils.js
@@ -0,0 +1,44 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import './common-test-setup-karma.js';
+
+// Run a11y audit on test fixture
+// The code is inspired by the
+// https://github.com/Polymer/web-component-tester/blob/master/data/a11ySuite.js
+export async function runA11yAudit(fixture, ignoredRules) {
+ fixture.instantiate();
+ await flush();
+ const axsConfig = new axs.AuditConfiguration();
+ axsConfig.scope = document.body;
+ axsConfig.showUnsupportedRulesWarning = false;
+ axsConfig.auditRulesToIgnore = ignoredRules;
+
+ const auditResults = axs.Audit.run(axsConfig);
+ const errors = [];
+ auditResults.forEach((result, index) => {
+ // only show applicable tests
+ if (result.result === 'FAIL') {
+ const title = result.rule.heading;
+ // fail test if audit result is FAIL
+ const error = axs.Audit.accessibilityErrorMessage(result);
+ errors.push(`${title}: ${error}`);
+ }
+ });
+ if (errors.length > 0) {
+ assert.fail(errors.join('\n') + '\n');
+ }
+}
diff --git a/polygerrit-ui/app/test/common-test-setup-karma.js b/polygerrit-ui/app/test/common-test-setup-karma.js
new file mode 100644
index 0000000..4fd3b03
--- /dev/null
+++ b/polygerrit-ui/app/test/common-test-setup-karma.js
@@ -0,0 +1,152 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './common-test-setup.js';
+import '@polymer/test-fixture/test-fixture.js';
+import 'chai/chai.js';
+self.assert = window.chai.assert;
+
+/**
+ * Triggers a flush of any pending events, observations, etc and calls you back
+ * after they have been processed if callback is passed; otherwise returns
+ * promise.
+ *
+ * @param {function()} callback
+ */
+function flush(callback) {
+ // Ideally, this function would be a call to Polymer.dom.flush, but that
+ // doesn't support a callback yet
+ // (https://github.com/Polymer/polymer-dev/issues/851)
+ window.Polymer.dom.flush();
+ if (callback) {
+ window.setTimeout(callback, 0);
+ } else {
+ return new Promise(resolve => {
+ window.setTimeout(resolve, 0);
+ });
+ }
+}
+
+self.flush = flush;
+
+class TestFixtureIdProvider {
+ static get instance() {
+ if (!TestFixtureIdProvider._instance) {
+ TestFixtureIdProvider._instance = new TestFixtureIdProvider();
+ }
+ return TestFixtureIdProvider._instance;
+ }
+
+ constructor() {
+ this.fixturesCount = 1;
+ }
+
+ generateNewFixtureId() {
+ this.fixturesCount++;
+ return `fixture-${this.fixturesCount}`;
+ }
+}
+
+class TestFixture {
+ constructor(fixtureId) {
+ this.fixtureId = fixtureId;
+ }
+
+ /**
+ * Create an instance of a fixture's template.
+ *
+ * @param {Object} model - see Data-bound sections at
+ * https://www.webcomponents.org/element/@polymer/test-fixture
+ * @return {HTMLElement | HTMLElement[]} - if the fixture's template contains
+ * a single element, returns the appropriated instantiated element.
+ * Otherwise, it return an array of all instantiated elements from the
+ * template.
+ */
+ instantiate(model) {
+ // The window.fixture method is defined in common-test-setup.js
+ return window.fixture(this.fixtureId, model);
+ }
+}
+
+/**
+ * Wraps provided template to a test-fixture tag and adds test-fixture to
+ * the document. You can use the html function to create a template.
+ *
+ * Example:
+ * import {html} from '@polymer/polymer/lib/utils/html-tag.js';
+ *
+ * // Create fixture at the root level of a test file
+ * const basicTestFixture = fixtureFromTemplate(html`
+ * <gr-cursor-manager cursor-target-class="targeted"></gr-cursor-manager>
+ * <ul>
+ * <li>A</li>
+ * <li>B</li>
+ * <li>C</li>
+ * <li>D</li>
+ * </ul>
+ * `);
+ * ...
+ * // Instantiate fixture when needed:
+ *
+ * suite('example') {
+ * let elements;
+ * setup(() => {
+ * elements = basicTestFixture.instantiate();
+ * });
+ * }
+ *
+ * @param {HTMLTemplateElement} template - a template for a fixture
+ * @return {TestFixture} - the instance of TestFixture class
+ */
+function fixtureFromTemplate(template) {
+ const fixtureId = TestFixtureIdProvider.instance.generateNewFixtureId();
+ const testFixture = document.createElement('test-fixture');
+ testFixture.setAttribute('id', fixtureId);
+ testFixture.appendChild(template);
+ document.body.appendChild(testFixture);
+ return new TestFixture(fixtureId);
+}
+
+/**
+ * Wraps provided tag to a test-fixture/template tags and adds test-fixture
+ * to the document.
+ *
+ * Example:
+ *
+ * // Create fixture at the root level of a test file
+ * const basicTestFixture = fixtureFromElement('gr-diff-view');
+ * ...
+ * // Instantiate fixture when needed:
+ *
+ * suite('example') {
+ * let element;
+ * setup(() => {
+ * element = basicTestFixture.instantiate();
+ * });
+ * }
+ *
+ * @param {HTMLTemplateElement} template - a template for a fixture
+ * @return {TestFixture} - the instance of TestFixture class
+ */
+function fixtureFromElement(tagName) {
+ const template = document.createElement('template');
+ template.innerHTML = `<${tagName}></${tagName}>`;
+ return fixtureFromTemplate(template);
+}
+
+window.fixtureFromTemplate = fixtureFromTemplate;
+window.fixtureFromElement = fixtureFromElement;
diff --git a/polygerrit-ui/app/test/common-test-setup.js b/polygerrit-ui/app/test/common-test-setup.js
index aea24da..db0d279 100644
--- a/polygerrit-ui/app/test/common-test-setup.js
+++ b/polygerrit-ui/app/test/common-test-setup.js
@@ -14,14 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// TODO(dmfilippov): remove bundled-polymer.js imports when the following issue
+// https://github.com/Polymer/polymer-resin/issues/9 is resolved.
import '../scripts/bundled-polymer.js';
import 'polymer-resin/standalone/polymer-resin.js';
import '@polymer/iron-test-helpers/iron-test-helpers.js';
import './test-router.js';
import {SafeTypes} from '../behaviors/safe-types-behavior/safe-types-behavior.js';
+import {appContext} from '../services/app-context.js';
import {initAppContext} from '../services/app-context-init.js';
import {_testOnly_resetPluginLoader} from '../elements/shared/gr-js-api-interface/gr-plugin-loader.js';
+import {grReportingMock} from '../services/gr-reporting/gr-reporting_mock.js';
+
+// Returns true if tests run under the Karma
+function isKarmaTest() {
+ return window.__karma__ !== undefined;
+}
security.polymer_resin.install({
allowedIdentifierPrefixes: [''],
@@ -57,28 +67,45 @@
// Note, that fixture(...) and stub(..) methods are registered different by
// WCT. This is why these methods implemented slightly different here.
const cleanups = [];
-if (!window.fixture) {
+if (isKarmaTest() || !window.fixture) {
+ // For karma always set our implementation
+ // (karma doesn't provide the fixture method)
window.fixture = function(fixtureId, model) {
// This method is inspired by WCT method
cleanups.push(() => document.getElementById(fixtureId).restore());
return document.getElementById(fixtureId).create(model);
};
} else {
+ // The following error is important for WCT tests.
+ // If window.fixture already installed by WCT at this point, WCT tests
+ // performance decreases rapidly.
+ // It allows to catch performance problems earlier.
throw new Error('window.fixture must be set before wct sets it');
}
// On the first call to the setup, WCT installs window.fixture
-// and widnow.stub methods
+// and window.stub methods
setup(() => {
// If the following asserts fails - then window.stub is
// overwritten by some other code.
assert.equal(cleanups.length, 0);
_testOnly_resetPluginLoader();
+
initAppContext();
+ function setMock(serviceName, setupMock) {
+ Object.defineProperty(appContext, serviceName, {
+ get() {
+ return setupMock;
+ },
+ });
+ }
+ setMock('reportingService', grReportingMock);
});
-if (window.stub) {
+if (isKarmaTest() || window.stub) {
+ // For karma always set our implementation
+ // (karma doesn't provide the stub method)
window.stub = function(tagName, implementation) {
// This method is inspired by WCT method
const proto = document.createElement(tagName).constructor.prototype;
@@ -91,6 +118,10 @@
});
};
} else {
+ // The following error is important for WCT tests.
+ // If window.fixture already installed by WCT at this point, WCT tests
+ // performance decreases rapidly.
+ // It allows to catch performance problems earlier.
throw new Error('window.stub must be set after wct sets it');
}
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock_test.js b/polygerrit-ui/app/test/mocks/comment-api.js
similarity index 100%
rename from polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock_test.js
rename to polygerrit-ui/app/test/mocks/comment-api.js
diff --git a/polygerrit-ui/app/test/mock-diff-response.js b/polygerrit-ui/app/test/mocks/diff-response.js
similarity index 100%
rename from polygerrit-ui/app/test/mock-diff-response.js
rename to polygerrit-ui/app/test/mocks/diff-response.js
diff --git a/polygerrit-ui/app/test/tests.js b/polygerrit-ui/app/test/tests.js
index 934d9e8..6892287 100644
--- a/polygerrit-ui/app/test/tests.js
+++ b/polygerrit-ui/app/test/tests.js
@@ -24,10 +24,9 @@
// Elements tests.
/* eslint-disable max-len */
const elements = [
- // This seemed to be flakey when it was farther down the list. Keep at the
+ // This seemed to be flaky when it was farther down the list. Keep at the
// beginning.
'gr-app_test.html',
- 'admin/gr-access-section/gr-access-section_test.html',
'admin/gr-admin-group-list/gr-admin-group-list_test.html',
'admin/gr-admin-view/gr-admin-view_test.html',
'admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html',
@@ -62,7 +61,6 @@
'change/gr-change-metadata/gr-change-metadata-it_test.html',
'change/gr-change-metadata/gr-change-metadata_test.html',
'change/gr-change-requirements/gr-change-requirements_test.html',
- 'change/gr-change-view/gr-change-view_test.html',
'change/gr-comment-list/gr-comment-list_test.html',
'change/gr-commit-info/gr-commit-info_test.html',
'change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html',
@@ -94,7 +92,6 @@
'core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.html',
'core/gr-main-header/gr-main-header_test.html',
'core/gr-navigation/gr-navigation_test.html',
- 'core/gr-reporting/gr-reporting_test.html',
'core/gr-router/gr-router_test.html',
'core/gr-search-bar/gr-search-bar_test.html',
'core/gr-smart-search/gr-smart-search_test.html',
@@ -112,7 +109,6 @@
'diff/gr-diff-selection/gr-diff-selection_test.html',
'diff/gr-diff-view/gr-diff-view_test.html',
'diff/gr-diff/gr-diff-group_test.html',
- 'diff/gr-diff/gr-diff_test.html',
'diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html',
'diff/gr-patch-range-select/gr-patch-range-select_test.html',
'diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html',
@@ -167,7 +163,6 @@
'shared/gr-comment/gr-comment_test.html',
'shared/gr-copy-clipboard/gr-copy-clipboard_test.html',
'shared/gr-count-string-formatter/gr-count-string-formatter_test.html',
- 'shared/gr-cursor-manager/gr-cursor-manager_test.html',
'shared/gr-date-formatter/gr-date-formatter_test.html',
'shared/gr-dialog/gr-dialog_test.html',
'shared/gr-diff-preferences/gr-diff-preferences_test.html',
@@ -223,7 +218,6 @@
// Behaviors tests.
/* eslint-disable max-len */
const behaviors = [
- 'async-foreach-behavior/async-foreach-behavior_test.html',
'base-url-behavior/base-url-behavior_test.html',
'docs-url-behavior/docs-url-behavior_test.html',
'dom-util-behavior/dom-util-behavior_test.html',
@@ -261,13 +255,19 @@
}
const services = [
+ 'app-context-init_test.html',
'flags_test.html',
+ 'gr-reporting/gr-reporting_test.html',
+ 'gr-reporting/gr-reporting_mock_test.html',
];
for (let file of services) {
file = servicesPath + file;
testFiles.push(file);
}
+// embed test
+testFiles.push('../embed/gr-diff-app-context-init_test.html');
+
/**
* Converts multiline string to a map<file_name, test_count>.
*
diff --git a/polygerrit-ui/app/types/custom-externs.js b/polygerrit-ui/app/types/custom-externs.js
index afa094c..bc95b3f 100644
--- a/polygerrit-ui/app/types/custom-externs.js
+++ b/polygerrit-ui/app/types/custom-externs.js
@@ -58,6 +58,5 @@
var GrRestApiHelper;
var GrDisplayNameUtils;
var GrReviewerSuggestionsProvider;
-var moment;
var page;
var util;
\ No newline at end of file
diff --git a/polygerrit-ui/app/types/types.js b/polygerrit-ui/app/types/types.js
index 5408eea..91909a6 100644
--- a/polygerrit-ui/app/types/types.js
+++ b/polygerrit-ui/app/types/types.js
@@ -309,3 +309,16 @@
* }}
*/
Gerrit.Comment;
+
+/**
+ * This contains path info used in diff, basePath
+ * is used on the left while path is used on the right.
+ *
+ * TODO(taoalpha): unify all *Range into one.
+ *
+ * @typedef {{
+ * basePath: ?string,
+ * path: string,
+ * }}
+ */
+Gerrit.FileRange;
\ No newline at end of file
diff --git a/polygerrit-ui/app/utils/date-util.js b/polygerrit-ui/app/utils/date-util.js
new file mode 100644
index 0000000..475fdc6
--- /dev/null
+++ b/polygerrit-ui/app/utils/date-util.js
@@ -0,0 +1,178 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const Duration = {
+ HOUR: 1000 * 60 * 60,
+ DAY: 1000 * 60 * 60 * 24,
+};
+
+export function parseDate(dateStr) {
+ // Timestamps are given in UTC and have the format
+ // "'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
+ // nanoseconds.
+ // Munge the date into an ISO 8061 format and parse that.
+ return new Date(dateStr.replace(' ', 'T') + 'Z');
+}
+
+export function isValidDate(date) {
+ return date instanceof Date && !isNaN(date);
+}
+
+// similar to fromNow from moment.js
+export function fromNow(date) {
+ const now = new Date();
+ const secondsAgo = Math.round((now - date) / 1000);
+ if (secondsAgo <= 44) return 'just now';
+ if (secondsAgo <= 89) return 'a minute ago';
+ const minutesAgo = Math.round(secondsAgo / 60);
+ if (minutesAgo <= 44) return `${minutesAgo} minutes ago`;
+ if (minutesAgo <= 89) return 'an hour ago';
+ const hoursAgo = Math.round(minutesAgo / 60);
+ if (hoursAgo <= 21) return `${hoursAgo} hours ago`;
+ if (hoursAgo <= 35) return 'a day ago';
+ const daysAgo = Math.round(hoursAgo / 24);
+ if (daysAgo <= 25) return `${daysAgo} days ago`;
+ if (daysAgo <= 45) return `a month ago`;
+ const monthsAgo = Math.round(daysAgo / 30);
+ if (daysAgo <= 319) return `${monthsAgo} months ago`;
+ if (daysAgo <= 547) return `a year ago`;
+ const yearsAgo = Math.round(daysAgo / 365);
+ return `${yearsAgo} years ago`;
+}
+
+/**
+ * Return true if date is within 24 hours and on the same day.
+ */
+export function isWithinDay(now, date) {
+ const diff = now - date;
+ return diff < Duration.DAY && date.getDay() == now.getDay();
+}
+
+/**
+ * Returns true if date is from one to six months.
+ */
+export function isWithinHalfYear(now, date) {
+ const diff = now - date;
+ return diff < 180 * Duration.DAY;
+}
+
+export function formatDate(date, format) {
+ const options = {};
+ if (format.includes('MM')) {
+ if (format.includes('MMM')) {
+ options.month = 'short';
+ } else {
+ options.month = '2-digit';
+ }
+ }
+ if (format.includes('YY')) {
+ if (format.includes('YYYY')) {
+ options.year = 'numeric';
+ } else {
+ options.year = '2-digit';
+ }
+ }
+
+ if (format.includes('DD')) {
+ options.day = '2-digit';
+ }
+
+ if (format.includes('HH')) {
+ options.hour = '2-digit';
+ options.hour12 = false;
+ }
+
+ if (format.includes('h')) {
+ options.hour = 'numeric';
+ options.hour12 = true;
+ }
+
+ if (format.includes('mm')) {
+ options.minute = '2-digit';
+ }
+
+ if (format.includes('ss')) {
+ options.second = '2-digit';
+ }
+ let locale = 'en-US';
+ // Workaround for Chrome 80, en-US is using h24 (midnight is 24:00),
+ // en-GB is using h23 (midnight is 00:00)
+ if (format.includes('HH')) {
+ locale = 'en-GB';
+ }
+
+ const dtf = new Intl.DateTimeFormat(locale, options);
+ const parts = dtf.formatToParts(date).filter(o => o.type != 'literal')
+ .reduce((acc, o) => {
+ acc[o.type] = o.value;
+ return acc;
+ }, {});
+ if (format.includes('YY')) {
+ if (format.includes('YYYY')) {
+ format = format.replace('YYYY', parts.year);
+ } else {
+ format = format.replace('YY', parts.year);
+ }
+ }
+
+ if (format.includes('DD')) {
+ format = format.replace('DD', parts.day);
+ }
+
+ if (format.includes('HH')) {
+ format = format.replace('HH', parts.hour);
+ }
+
+ if (format.includes('h')) {
+ format = format.replace('h', parts.hour);
+ }
+
+ if (format.includes('mm')) {
+ format = format.replace('mm', parts.minute);
+ }
+
+ if (format.includes('ss')) {
+ format = format.replace('ss', parts.second);
+ }
+
+ if (format.includes('A')) {
+ if (parts.dayperiod) {
+ // Workaround for chrome 70 and below
+ format = format.replace('A', parts.dayperiod.toUpperCase());
+ } else {
+ format = format.replace('A', parts.dayPeriod.toUpperCase());
+ }
+ }
+ if (format.includes('MM')) {
+ if (format.includes('MMM')) {
+ format = format.replace('MMM', parts.month);
+ } else {
+ format = format.replace('MM', parts.month);
+ }
+ }
+ return format;
+}
+
+export function utcOffsetString() {
+ const now = new Date();
+ const tzo = -now.getTimezoneOffset();
+ const pad = num => {
+ const norm = Math.floor(Math.abs(num));
+ return (norm < 10 ? '0' : '') + norm;
+ };
+ return ` UTC${tzo >= 0 ? '+' : '-'}${pad(tzo / 60)}:${pad(tzo%60)}`;
+}
\ No newline at end of file
diff --git a/polygerrit-ui/app/utils/date-util_test.js b/polygerrit-ui/app/utils/date-util_test.js
new file mode 100644
index 0000000..7b22cc6
--- /dev/null
+++ b/polygerrit-ui/app/utils/date-util_test.js
@@ -0,0 +1,121 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '../test/common-test-setup-karma.js';
+import {isValidDate, parseDate, fromNow, isWithinDay, isWithinHalfYear, formatDate} from './date-util.js';
+
+suite('date-util tests', () => {
+ suite('parseDate', () => {
+ test('parseDate server date', () => {
+ const parsed = parseDate('2015-09-15 20:34:00.000000000');
+ assert.equal('2015-09-15T20:34:00.000Z', parsed.toISOString());
+ });
+ });
+
+ suite('isValidDate', () => {
+ test('date is valid', () => {
+ assert.isTrue(isValidDate(new Date()));
+ });
+ test('broken date is invalid', () => {
+ assert.isFalse(isValidDate(new Date('xxx')));
+ });
+ });
+
+ suite('fromNow', () => {
+ test('test all variants', () => {
+ const fakeNow = new Date('May 08 2020 12:00:00');
+ sinon.useFakeTimers(fakeNow.getTime());
+ assert.equal('just now', fromNow(new Date('May 08 2020 11:59:30')));
+ assert.equal('a minute ago', fromNow(new Date('May 08 2020 11:59:00')));
+ assert.equal('5 minutes ago', fromNow(new Date('May 08 2020 11:55:00')));
+ assert.equal('an hour ago', fromNow(new Date('May 08 2020 11:00:00')));
+ assert.equal('3 hours ago', fromNow(new Date('May 08 2020 9:00:00')));
+ assert.equal('a day ago', fromNow(new Date('May 07 2020 12:00:00')));
+ assert.equal('3 days ago', fromNow(new Date('May 05 2020 12:00:00')));
+ assert.equal('a month ago', fromNow(new Date('Apr 05 2020 12:00:00')));
+ assert.equal('2 months ago', fromNow(new Date('Mar 05 2020 12:00:00')));
+ assert.equal('a year ago', fromNow(new Date('May 05 2019 12:00:00')));
+ assert.equal('10 years ago', fromNow(new Date('May 05 2010 12:00:00')));
+ });
+ });
+
+ suite('isWithinDay', () => {
+ test('basics works', () => {
+ assert.isTrue(isWithinDay(new Date('May 08 2020 12:00:00'),
+ new Date('May 08 2020 02:00:00')));
+ assert.isFalse(isWithinDay(new Date('May 08 2020 12:00:00'),
+ new Date('May 07 2020 12:00:00')));
+ });
+ });
+
+ suite('isWithinHalfYear', () => {
+ test('basics works', () => {
+ assert.isTrue(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
+ new Date('Feb 08 2020 12:00:00')));
+ assert.isFalse(isWithinHalfYear(new Date('May 08 2020 12:00:00'),
+ new Date('Nov 07 2019 12:00:00')));
+ });
+ });
+
+ suite('formatDate', () => {
+ test('works for standard format', () => {
+ const stdFormat = 'MMM DD, YYYY';
+ assert.equal('May 08, 2020',
+ formatDate(new Date('May 08 2020 12:00:00'), stdFormat));
+ assert.equal('Feb 28, 2020',
+ formatDate(new Date('Feb 28 2020 12:00:00'), stdFormat));
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal('Feb 28, 2020 12:01:12',
+ formatDate(new Date('Feb 28 2020 12:01:12'), stdFormat + ' '
+ + time24Format));
+ });
+ test('works for euro format', () => {
+ const euroFormat = 'DD.MM.YYYY';
+ assert.equal('01.12.2019',
+ formatDate(new Date('Dec 01 2019 12:00:00'), euroFormat));
+ assert.equal('20.01.2002',
+ formatDate(new Date('Jan 20 2002 12:00:00'), euroFormat));
+
+ const time24Format = 'HH:mm:ss';
+ assert.equal('28.02.2020 00:01:12',
+ formatDate(new Date('Feb 28 2020 00:01:12'), euroFormat + ' '
+ + time24Format));
+ });
+ test('works for iso format', () => {
+ const isoFormat = 'YYYY-MM-DD';
+ assert.equal('2015-01-01',
+ formatDate(new Date('Jan 01 2015 12:00:00'), isoFormat));
+ assert.equal('2013-07-03',
+ formatDate(new Date('Jul 03 2013 12:00:00'), isoFormat));
+
+ const timeFormat = 'h:mm:ss A';
+ assert.equal('2013-07-03 5:00:00 AM',
+ formatDate(new Date('Jul 03 2013 05:00:00'), isoFormat + ' '
+ + timeFormat));
+ assert.equal('2013-07-03 5:00:00 PM',
+ formatDate(new Date('Jul 03 2013 17:00:00'), isoFormat + ' '
+ + timeFormat));
+ });
+ test('h:mm:ss A shows correctly midnight and midday', () => {
+ const timeFormat = 'h:mm A';
+ assert.equal('12:14 PM',
+ formatDate(new Date('Jul 03 2013 12:14:00'), timeFormat));
+ assert.equal('12:15 AM',
+ formatDate(new Date('Jul 03 2013 00:15:00'), timeFormat));
+ });
+ });
+});
\ No newline at end of file
diff --git a/polygerrit-ui/app/wct_test.sh b/polygerrit-ui/app/wct_test.sh
index 42b98ab..829a507 100755
--- a/polygerrit-ui/app/wct_test.sh
+++ b/polygerrit-ui/app/wct_test.sh
@@ -14,7 +14,7 @@
# Copy ui_npm, so it will override ui_dev_npm modules (in case of conflicts)
# Because browser always requests specific exact files (i.e. not a directory),
-# it always receives file from ui_npm. It can broke WCT itself but luckely it works.
+# it always receives file from ui_npm. It can broke WCT itself but luckily it works.
cp -R -L ./external/ui_npm/node_modules/* $t/node_modules
cp -R -L ./polygerrit-ui/app/* $t/
@@ -25,13 +25,13 @@
echo "export const config=$JSON_CONFIG;" > ./test/suite_conf.js
echo "export const testsPerFileString=\`" >> ./test/suite_conf.js
# Count number of tests in each file.
-# We don't need accurate data, use simpliest method
+# We don't need accurate data, use simplest method
# TODO(dmfilippov): collect data only once
# In the current implementation, the same data is collected for each split,
# It takes less than a second which many times less than the overall wct test time
grep -rnw '.' --include=\*_test.html -e "test(" -c >> ./test/suite_conf.js
echo "\`;" >>./test/suite_conf.js
-# If wct doesn't receive any paramenters, it fails (can't find files)
+# If wct doesn't receive any parameters, it fails (can't find files)
# Pass --config-file as a parameter to have some arguments in command line
$root_dir/$1 --config-file wct.conf.js ${WCT_ARGS}
diff --git a/polygerrit-ui/app/yarn.lock b/polygerrit-ui/app/yarn.lock
index 5724ffa..821b724 100644
--- a/polygerrit-ui/app/yarn.lock
+++ b/polygerrit-ui/app/yarn.lock
@@ -338,11 +338,6 @@
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
-moment@^2.24.0:
- version "2.24.0"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
- integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
-
page@^1.11.5:
version "1.11.5"
resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
diff --git a/polygerrit-ui/karma.conf.js b/polygerrit-ui/karma.conf.js
new file mode 100644
index 0000000..744c234
--- /dev/null
+++ b/polygerrit-ui/karma.conf.js
@@ -0,0 +1,152 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const runUnderBazel = !!process.env["RUNFILES_DIR"];
+const path = require('path');
+
+function getModulesDir() {
+ if(runUnderBazel) {
+ // Run under bazel
+ return [
+ `external/ui_npm/node_modules`,
+ `external/ui_dev_npm/node_modules`
+ ];
+ }
+
+ // Run from intellij or npm run test:kdebug
+ return [
+ path.join(__dirname, 'app/node_modules'),
+ path.join(__dirname, 'node_modules'),
+ ];
+}
+
+function getUiDevNpmFilePath(importPath) {
+ if(runUnderBazel) {
+ return `external/ui_dev_npm/node_modules/${importPath}`;
+ }
+ else {
+ return `polygerrit-ui/node_modules/${importPath}`
+ }
+}
+
+module.exports = function(config) {
+ const testFilesLocationPattern =
+ 'polygerrit-ui/app/**/!(template_test_srcs)/';
+ // Use --test-files to specify pattern for a test files.
+ // It can be just a file name, without a path:
+ // --test-files async-foreach-behavior_test.js
+ // If you specify --test-files without pattern, it gets true value
+ // In this case we ill run all tests (usefull for package.json "debugtest"
+ // script)
+ const testFilesPattern = (typeof config.testFiles == 'string') ?
+ testFilesLocationPattern + config.testFiles :
+ testFilesLocationPattern + '*_test.js';
+ config.set({
+ // base path that will be used to resolve all patterns (eg. files, exclude)
+ basePath: '../',
+ plugins: [
+ // Do not use karma-* to load all installed plugin
+ // This can lead to unexpected behavior under bazel
+ // if you forget to add a plugin in a bazel rule.
+ require.resolve('@open-wc/karma-esm'),
+ 'karma-mocha',
+ 'karma-chrome-launcher',
+ 'karma-mocha-reporter',
+ ],
+ // frameworks to use
+ // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+ frameworks: ['mocha', 'esm'],
+
+ // list of files / patterns to load in the browser
+ files: [
+ getUiDevNpmFilePath('accessibility-developer-tools/dist/js/axs_testing.js'),
+ getUiDevNpmFilePath('sinon/pkg/sinon.js'),
+ { pattern: testFilesPattern, type: 'module' },
+ ],
+ esm: {
+ nodeResolve: true,
+ moduleDirs: getModulesDir(),
+ // Bazel and yarn uses symlinks for files.
+ // preserveSymlinks is necessary for correct modules paths resolving
+ preserveSymlinks: true,
+ // By default, esm-dev-server uses 'auto' compatibility mode.
+ // In the 'auto' mode it incorrectly applies polyfills and
+ // breaks tests in some browser versions
+ // (for example, Chrome 69 on gerrit-ci).
+ compatibility: 'none',
+ },
+ // test results reporter to use
+ // possible values: 'dots', 'progress'
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+ reporters: ['mocha'],
+
+
+ // web server port
+ port: 9876,
+
+
+ // enable / disable colors in the output (reporters and logs)
+ colors: true,
+
+
+ // level of logging
+ // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+ logLevel: config.LOG_INFO,
+
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch: false,
+
+
+ // start these browsers
+ // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+ browsers: ["CustomChromeHeadless"],
+ browserForDebugging: "CustomChromeHeadlessWithDebugPort",
+
+
+ // Continuous Integration mode
+ // if true, Karma captures browsers, runs the tests and exits
+ singleRun: true,
+
+ // Concurrency level
+ // how many browser should be started simultaneous
+ concurrency: Infinity,
+
+ client: {
+ mocha: {
+ ui: 'tdd',
+ timeout: 5000,
+ }
+ },
+
+ customLaunchers: {
+ // Based on https://developers.google.com/web/updates/2017/06/headless-karma-mocha-chai
+ "CustomChromeHeadless": {
+ base: 'ChromeHeadless',
+ flags: ['--disable-translate', '--disable-extensions'],
+ },
+ "ChromeDev": {
+ base: 'Chrome',
+ flags: ['--disable-extensions', ' --auto-open-devtools-for-tabs'],
+ },
+ "CustomChromeHeadlessWithDebugPort": {
+ base: 'CustomChromeHeadless',
+ flags: ['--remote-debugging-port=9222'],
+ }
+ }
+ });
+};
diff --git a/polygerrit-ui/karma_test.sh b/polygerrit-ui/karma_test.sh
new file mode 100755
index 0000000..5fab442
--- /dev/null
+++ b/polygerrit-ui/karma_test.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+set -euo pipefail
+./$1 start $2 --single-run
diff --git a/polygerrit-ui/package.json b/polygerrit-ui/package.json
index 3d35e3e..527763b 100644
--- a/polygerrit-ui/package.json
+++ b/polygerrit-ui/package.json
@@ -4,12 +4,23 @@
"browser": true,
"dependencies": {},
"devDependencies": {
+ "@open-wc/karma-esm": "^2.13.21",
"@polymer/iron-test-helpers": "^3.0.1",
+ "@polymer/test-fixture": "^4.0.2",
+ "accessibility-developer-tools": "^2.12.0",
"chai": "^4.2.0",
- "mocha": "^6.2.2",
+ "karma": "^4.4.1",
+ "karma-chrome-launcher": "^3.1.0",
+ "karma-mocha": "^2.0.1",
+ "karma-mocha-reporter": "^2.2.5",
+ "lodash": "^4.17.15",
+ "mocha": "^7.1.1",
"wct-browser-legacy": "^1.0.2",
"web-component-tester": "^6.9.2"
},
+ "scripts": {
+ "postinstall": "selenium-standalone install"
+ },
"license": "Apache-2.0",
"private": true
}
diff --git a/polygerrit-ui/yarn.lock b/polygerrit-ui/yarn.lock
index 12d39aa..5ad28b6 100644
--- a/polygerrit-ui/yarn.lock
+++ b/polygerrit-ui/yarn.lock
@@ -9,6 +9,15 @@
dependencies:
"@babel/highlight" "^7.8.3"
+"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c"
+ integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g==
+ dependencies:
+ browserslist "^4.9.1"
+ invariant "^2.2.4"
+ semver "^5.5.0"
+
"@babel/core@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941"
@@ -30,6 +39,28 @@
semver "^5.4.1"
source-map "^0.5.0"
+"@babel/core@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e"
+ integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@babel/generator" "^7.9.0"
+ "@babel/helper-module-transforms" "^7.9.0"
+ "@babel/helpers" "^7.9.0"
+ "@babel/parser" "^7.9.0"
+ "@babel/template" "^7.8.6"
+ "@babel/traverse" "^7.9.0"
+ "@babel/types" "^7.9.0"
+ convert-source-map "^1.7.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.1"
+ json5 "^2.1.2"
+ lodash "^4.17.13"
+ resolve "^1.3.2"
+ semver "^5.4.1"
+ source-map "^0.5.0"
+
"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03"
@@ -40,6 +71,16 @@
lodash "^4.17.13"
source-map "^0.5.0"
+"@babel/generator@^7.4.0", "@babel/generator@^7.9.0":
+ version "7.9.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce"
+ integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==
+ dependencies:
+ "@babel/types" "^7.9.0"
+ jsesc "^2.5.1"
+ lodash "^4.17.13"
+ source-map "^0.5.0"
+
"@babel/helper-annotate-as-pure@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
@@ -64,6 +105,17 @@
"@babel/traverse" "^7.8.3"
"@babel/types" "^7.8.3"
+"@babel/helper-compilation-targets@^7.8.7":
+ version "7.8.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde"
+ integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==
+ dependencies:
+ "@babel/compat-data" "^7.8.6"
+ browserslist "^4.9.1"
+ invariant "^2.2.4"
+ levenary "^1.1.1"
+ semver "^5.5.0"
+
"@babel/helper-create-regexp-features-plugin@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79"
@@ -72,6 +124,15 @@
"@babel/helper-regex" "^7.8.3"
regexpu-core "^4.6.0"
+"@babel/helper-create-regexp-features-plugin@^7.8.8":
+ version "7.8.8"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087"
+ integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.8.3"
+ "@babel/helper-regex" "^7.8.3"
+ regexpu-core "^4.7.0"
+
"@babel/helper-define-map@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15"
@@ -138,6 +199,19 @@
"@babel/types" "^7.8.3"
lodash "^4.17.13"
+"@babel/helper-module-transforms@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5"
+ integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==
+ dependencies:
+ "@babel/helper-module-imports" "^7.8.3"
+ "@babel/helper-replace-supers" "^7.8.6"
+ "@babel/helper-simple-access" "^7.8.3"
+ "@babel/helper-split-export-declaration" "^7.8.3"
+ "@babel/template" "^7.8.6"
+ "@babel/types" "^7.9.0"
+ lodash "^4.17.13"
+
"@babel/helper-optimise-call-expression@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
@@ -145,7 +219,7 @@
dependencies:
"@babel/types" "^7.8.3"
-"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
@@ -178,6 +252,16 @@
"@babel/traverse" "^7.8.3"
"@babel/types" "^7.8.3"
+"@babel/helper-replace-supers@^7.8.6":
+ version "7.8.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8"
+ integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==
+ dependencies:
+ "@babel/helper-member-expression-to-functions" "^7.8.3"
+ "@babel/helper-optimise-call-expression" "^7.8.3"
+ "@babel/traverse" "^7.8.6"
+ "@babel/types" "^7.8.6"
+
"@babel/helper-simple-access@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
@@ -193,6 +277,11 @@
dependencies:
"@babel/types" "^7.8.3"
+"@babel/helper-validator-identifier@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed"
+ integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==
+
"@babel/helper-wrap-function@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
@@ -212,6 +301,15 @@
"@babel/traverse" "^7.8.3"
"@babel/types" "^7.8.3"
+"@babel/helpers@^7.9.0":
+ version "7.9.2"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f"
+ integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==
+ dependencies:
+ "@babel/template" "^7.8.3"
+ "@babel/traverse" "^7.9.0"
+ "@babel/types" "^7.9.0"
+
"@babel/highlight@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
@@ -221,6 +319,11 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
+"@babel/parser@^7.4.3", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0":
+ version "7.9.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8"
+ integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==
+
"@babel/parser@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081"
@@ -233,7 +336,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-proposal-async-generator-functions@^7.0.0":
+"@babel/plugin-proposal-async-generator-functions@^7.0.0", "@babel/plugin-proposal-async-generator-functions@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==
@@ -242,6 +345,38 @@
"@babel/helper-remap-async-to-generator" "^7.8.3"
"@babel/plugin-syntax-async-generators" "^7.8.0"
+"@babel/plugin-proposal-dynamic-import@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054"
+ integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+
+"@babel/plugin-proposal-json-strings@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b"
+ integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.0"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2"
+ integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+
+"@babel/plugin-proposal-numeric-separator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8"
+ integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+
"@babel/plugin-proposal-object-rest-spread@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
@@ -250,6 +385,38 @@
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+"@babel/plugin-proposal-object-rest-spread@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f"
+ integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+
+"@babel/plugin-proposal-optional-catch-binding@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9"
+ integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+
+"@babel/plugin-proposal-optional-chaining@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58"
+ integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+
+"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3":
+ version "7.8.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d"
+ integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.8.8"
+ "@babel/helper-plugin-utils" "^7.8.3"
+
"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.0":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -257,20 +424,48 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-dynamic-import@^7.0.0":
+"@babel/plugin-syntax-class-properties@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz#6cb933a8872c8d359bfde69bbeaae5162fd1e8f7"
+ integrity sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-dynamic-import@^7.0.0", "@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-import-meta@^7.0.0":
+"@babel/plugin-syntax-import-meta@^7.0.0", "@babel/plugin-syntax-import-meta@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.8.3.tgz#230afff79d3ccc215b5944b438e4e266daf3d84d"
integrity sha512-vYiGd4wQ9gx0Lngb7+bPCwQXGK/PR6FeTIJ+TIOlq+OfOKG/kCAOO2+IBac3oMM9qV7/fU76hfcqxUaLKZf1hQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
+"@babel/plugin-syntax-json-strings@^7.8.0":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+ integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+ integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f"
+ integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
@@ -278,14 +473,35 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-transform-arrow-functions@^7.0.0":
+"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+ integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+ integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-top-level-await@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391"
+ integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-arrow-functions@^7.0.0", "@babel/plugin-transform-arrow-functions@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6"
integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-async-to-generator@^7.0.0":
+"@babel/plugin-transform-async-to-generator@^7.0.0", "@babel/plugin-transform-async-to-generator@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086"
integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==
@@ -294,14 +510,14 @@
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/helper-remap-async-to-generator" "^7.8.3"
-"@babel/plugin-transform-block-scoped-functions@^7.0.0":
+"@babel/plugin-transform-block-scoped-functions@^7.0.0", "@babel/plugin-transform-block-scoped-functions@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3"
integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-block-scoping@^7.0.0":
+"@babel/plugin-transform-block-scoping@^7.0.0", "@babel/plugin-transform-block-scoping@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a"
integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==
@@ -323,7 +539,21 @@
"@babel/helper-split-export-declaration" "^7.8.3"
globals "^11.1.0"
-"@babel/plugin-transform-computed-properties@^7.0.0":
+"@babel/plugin-transform-classes@^7.9.0":
+ version "7.9.2"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d"
+ integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.8.3"
+ "@babel/helper-define-map" "^7.8.3"
+ "@babel/helper-function-name" "^7.8.3"
+ "@babel/helper-optimise-call-expression" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-replace-supers" "^7.8.6"
+ "@babel/helper-split-export-declaration" "^7.8.3"
+ globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.0.0", "@babel/plugin-transform-computed-properties@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b"
integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==
@@ -337,14 +567,29 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-duplicate-keys@^7.0.0":
+"@babel/plugin-transform-destructuring@^7.8.3":
+ version "7.8.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b"
+ integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e"
+ integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-duplicate-keys@^7.0.0", "@babel/plugin-transform-duplicate-keys@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1"
integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-exponentiation-operator@^7.0.0":
+"@babel/plugin-transform-exponentiation-operator@^7.0.0", "@babel/plugin-transform-exponentiation-operator@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7"
integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==
@@ -359,7 +604,14 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-function-name@^7.0.0":
+"@babel/plugin-transform-for-of@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e"
+ integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-function-name@^7.0.0", "@babel/plugin-transform-function-name@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b"
integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==
@@ -374,13 +626,20 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-literals@^7.0.0":
+"@babel/plugin-transform-literals@^7.0.0", "@babel/plugin-transform-literals@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1"
integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
+"@babel/plugin-transform-member-expression-literals@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410"
+ integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
"@babel/plugin-transform-modules-amd@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5"
@@ -390,7 +649,58 @@
"@babel/helper-plugin-utils" "^7.8.3"
babel-plugin-dynamic-import-node "^2.3.0"
-"@babel/plugin-transform-object-super@^7.0.0":
+"@babel/plugin-transform-modules-amd@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4"
+ integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.9.0"
+ "@babel/helper-plugin-utils" "^7.8.3"
+ babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-commonjs@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940"
+ integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.9.0"
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-simple-access" "^7.8.3"
+ babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-systemjs@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90"
+ integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==
+ dependencies:
+ "@babel/helper-hoist-variables" "^7.8.3"
+ "@babel/helper-module-transforms" "^7.9.0"
+ "@babel/helper-plugin-utils" "^7.8.3"
+ babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-umd@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697"
+ integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.9.0"
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c"
+ integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.8.3"
+
+"@babel/plugin-transform-new-target@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43"
+ integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-object-super@^7.0.0", "@babel/plugin-transform-object-super@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725"
integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==
@@ -407,6 +717,21 @@
"@babel/helper-get-function-arity" "^7.8.3"
"@babel/helper-plugin-utils" "^7.8.3"
+"@babel/plugin-transform-parameters@^7.8.7":
+ version "7.9.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a"
+ integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg==
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-property-literals@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263"
+ integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
"@babel/plugin-transform-regenerator@^7.0.0":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8"
@@ -414,21 +739,35 @@
dependencies:
regenerator-transform "^0.14.0"
-"@babel/plugin-transform-shorthand-properties@^7.0.0":
+"@babel/plugin-transform-regenerator@^7.8.7":
+ version "7.8.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8"
+ integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==
+ dependencies:
+ regenerator-transform "^0.14.2"
+
+"@babel/plugin-transform-reserved-words@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5"
+ integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8"
integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-spread@^7.0.0":
+"@babel/plugin-transform-spread@^7.0.0", "@babel/plugin-transform-spread@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8"
integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-sticky-regex@^7.0.0":
+"@babel/plugin-transform-sticky-regex@^7.0.0", "@babel/plugin-transform-sticky-regex@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100"
integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==
@@ -436,7 +775,7 @@
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/helper-regex" "^7.8.3"
-"@babel/plugin-transform-template-literals@^7.0.0":
+"@babel/plugin-transform-template-literals@^7.0.0", "@babel/plugin-transform-template-literals@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80"
integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==
@@ -451,7 +790,14 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.3"
-"@babel/plugin-transform-unicode-regex@^7.0.0":
+"@babel/plugin-transform-typeof-symbol@^7.8.4":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412"
+ integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-transform-unicode-regex@^7.0.0", "@babel/plugin-transform-unicode-regex@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad"
integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==
@@ -459,6 +805,99 @@
"@babel/helper-create-regexp-features-plugin" "^7.8.3"
"@babel/helper-plugin-utils" "^7.8.3"
+"@babel/preset-env@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8"
+ integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==
+ dependencies:
+ "@babel/compat-data" "^7.9.0"
+ "@babel/helper-compilation-targets" "^7.8.7"
+ "@babel/helper-module-imports" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/plugin-proposal-async-generator-functions" "^7.8.3"
+ "@babel/plugin-proposal-dynamic-import" "^7.8.3"
+ "@babel/plugin-proposal-json-strings" "^7.8.3"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-proposal-numeric-separator" "^7.8.3"
+ "@babel/plugin-proposal-object-rest-spread" "^7.9.0"
+ "@babel/plugin-proposal-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-proposal-optional-chaining" "^7.9.0"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.8.3"
+ "@babel/plugin-syntax-async-generators" "^7.8.0"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+ "@babel/plugin-syntax-json-strings" "^7.8.0"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.0"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+ "@babel/plugin-syntax-top-level-await" "^7.8.3"
+ "@babel/plugin-transform-arrow-functions" "^7.8.3"
+ "@babel/plugin-transform-async-to-generator" "^7.8.3"
+ "@babel/plugin-transform-block-scoped-functions" "^7.8.3"
+ "@babel/plugin-transform-block-scoping" "^7.8.3"
+ "@babel/plugin-transform-classes" "^7.9.0"
+ "@babel/plugin-transform-computed-properties" "^7.8.3"
+ "@babel/plugin-transform-destructuring" "^7.8.3"
+ "@babel/plugin-transform-dotall-regex" "^7.8.3"
+ "@babel/plugin-transform-duplicate-keys" "^7.8.3"
+ "@babel/plugin-transform-exponentiation-operator" "^7.8.3"
+ "@babel/plugin-transform-for-of" "^7.9.0"
+ "@babel/plugin-transform-function-name" "^7.8.3"
+ "@babel/plugin-transform-literals" "^7.8.3"
+ "@babel/plugin-transform-member-expression-literals" "^7.8.3"
+ "@babel/plugin-transform-modules-amd" "^7.9.0"
+ "@babel/plugin-transform-modules-commonjs" "^7.9.0"
+ "@babel/plugin-transform-modules-systemjs" "^7.9.0"
+ "@babel/plugin-transform-modules-umd" "^7.9.0"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3"
+ "@babel/plugin-transform-new-target" "^7.8.3"
+ "@babel/plugin-transform-object-super" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.8.7"
+ "@babel/plugin-transform-property-literals" "^7.8.3"
+ "@babel/plugin-transform-regenerator" "^7.8.7"
+ "@babel/plugin-transform-reserved-words" "^7.8.3"
+ "@babel/plugin-transform-shorthand-properties" "^7.8.3"
+ "@babel/plugin-transform-spread" "^7.8.3"
+ "@babel/plugin-transform-sticky-regex" "^7.8.3"
+ "@babel/plugin-transform-template-literals" "^7.8.3"
+ "@babel/plugin-transform-typeof-symbol" "^7.8.4"
+ "@babel/plugin-transform-unicode-regex" "^7.8.3"
+ "@babel/preset-modules" "^0.1.3"
+ "@babel/types" "^7.9.0"
+ browserslist "^4.9.1"
+ core-js-compat "^3.6.2"
+ invariant "^2.2.2"
+ levenary "^1.1.1"
+ semver "^5.5.0"
+
+"@babel/preset-modules@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72"
+ integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
+ "@babel/plugin-transform-dotall-regex" "^7.4.4"
+ "@babel/types" "^7.4.4"
+ esutils "^2.0.2"
+
+"@babel/runtime@^7.8.4":
+ version "7.9.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
+ integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
+"@babel/template@^7.4.0", "@babel/template@^7.8.6":
+ version "7.8.6"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
+ integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@babel/parser" "^7.8.6"
+ "@babel/types" "^7.8.6"
+
"@babel/template@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
@@ -483,6 +922,21 @@
globals "^11.1.0"
lodash "^4.17.13"
+"@babel/traverse@^7.4.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892"
+ integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@babel/generator" "^7.9.0"
+ "@babel/helper-function-name" "^7.8.3"
+ "@babel/helper-split-export-declaration" "^7.8.3"
+ "@babel/parser" "^7.9.0"
+ "@babel/types" "^7.9.0"
+ debug "^4.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.13"
+
"@babel/types@^7.0.0-beta.42", "@babel/types@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
@@ -492,6 +946,62 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.8.6", "@babel/types@^7.9.0":
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5"
+ integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.9.0"
+ lodash "^4.17.13"
+ to-fast-properties "^2.0.0"
+
+"@open-wc/building-utils@^2.16.1":
+ version "2.16.1"
+ resolved "https://registry.yarnpkg.com/@open-wc/building-utils/-/building-utils-2.16.1.tgz#093d74881b996fe9497d628cdf55b6757422d894"
+ integrity sha512-0nUktFyelvSbCc8+T4w4PCyIy3i8blOFS0/EiG5xbVJ0HejDPQLTSmRBpZkn6X57tHhwUfjIdv0EAQuo2sbHEw==
+ dependencies:
+ "@babel/core" "^7.9.0"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+ "@webcomponents/shadycss" "^1.9.4"
+ "@webcomponents/webcomponentsjs" "^2.4.0"
+ arrify "^2.0.1"
+ browserslist "^4.9.1"
+ chokidar "^3.0.0"
+ clean-css "^4.2.1"
+ clone "^2.1.2"
+ core-js-bundle "^3.6.0"
+ deepmerge "^3.2.0"
+ es-module-shims "^0.4.6"
+ html-minifier "^4.0.0"
+ lru-cache "^5.1.1"
+ minimatch "^3.0.4"
+ parse5 "^5.1.1"
+ path-is-inside "^1.0.2"
+ regenerator-runtime "^0.13.3"
+ resolve "^1.11.1"
+ rimraf "^3.0.0"
+ shady-css-scoped-element "^0.0.2"
+ systemjs "^4.0.0"
+ terser "^4.6.4"
+ valid-url "^1.0.9"
+ whatwg-fetch "^3.0.0"
+ whatwg-url "^7.0.0"
+
+"@open-wc/karma-esm@^2.13.21":
+ version "2.13.21"
+ resolved "https://registry.yarnpkg.com/@open-wc/karma-esm/-/karma-esm-2.13.21.tgz#bef38b4e153b5728a6934de8a926d8bd9b9bb4db"
+ integrity sha512-qJREvj5HbYpUb6IeQXXiylPtqSnknUhBeK3PmhlnVdsXCeuPucmKJHbInd8ThYjX5/UJSp/cWe/Dt4H8GqHPHw==
+ dependencies:
+ "@open-wc/building-utils" "^2.16.1"
+ babel-plugin-istanbul "^5.1.4"
+ chokidar "^3.0.0"
+ deepmerge "^3.2.0"
+ es-dev-server "^1.46.0"
+ minimatch "^3.0.4"
+ node-fetch "^2.6.0"
+ portfinder "^1.0.21"
+ request "^2.88.0"
+
"@polymer/esm-amd-loader@^1.0.0":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
@@ -526,6 +1036,29 @@
resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-3.0.0-pre.21.tgz#85152207cb0bf57caebc191c80bb0fdb6952614e"
integrity sha512-IxzUe6YzaORzUksafHAXHprV29YncOJgr0+1zNAifl0/f+cb5iAd4IWUrnsnVFHG5UGTLjvis5RgV6vvIZPDrA==
+"@polymer/test-fixture@^4.0.2":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-4.0.2.tgz#2f4777ecdcfb22ee000db35a05e0edf27c722c19"
+ integrity sha512-tLX8tFE4mkc4p84YG5239G0hbgTVv2irZYrSyO0OblUqIRbRoCPmbydm3HRFQkJeAB3rPCtyeZ2roJULsmTG3A==
+
+"@rollup/plugin-node-resolve@^6.1.0":
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-6.1.0.tgz#0d2909f4bf606ae34d43a9bc8be06a9b0c850cf0"
+ integrity sha512-Cv7PDIvxdE40SWilY5WgZpqfIUEaDxFxs89zCAHjqyRwlTSuql4M5hjIuc5QYJkOH0/vyiyNXKD72O+LhRipGA==
+ dependencies:
+ "@rollup/pluginutils" "^3.0.0"
+ "@types/resolve" "0.0.8"
+ builtin-modules "^3.1.0"
+ is-module "^1.0.0"
+ resolve "^1.11.1"
+
+"@rollup/pluginutils@^3.0.0":
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.8.tgz#4e94d128d94b90699e517ef045422960d18c8fde"
+ integrity sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw==
+ dependencies:
+ estree-walker "^1.0.1"
+
"@types/babel-generator@^6.25.1":
version "6.25.3"
resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
@@ -719,7 +1252,7 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
-"@types/minimatch@*", "@types/minimatch@^3.0.1":
+"@types/minimatch@*", "@types/minimatch@^3.0.1", "@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
@@ -799,6 +1332,13 @@
dependencies:
"@types/node" "*"
+"@types/resolve@0.0.8":
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
+ integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
+ dependencies:
+ "@types/node" "*"
+
"@types/serve-static@*", "@types/serve-static@^1.7.31":
version "1.13.3"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
@@ -867,6 +1407,11 @@
resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+"@webcomponents/shadycss@^1.9.4":
+ version "1.9.6"
+ resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.6.tgz#a8c5db867e49200a05cf8d5008029c09b7861979"
+ integrity sha512-5fFjvP0jQJZoXK6YzYeYcIDGJ5oEsdjr1L9VaYLw5yxNd4aRz4srMpwCwldeNG0A6Hvr9igbG7fCsBeiiCXd7A==
+
"@webcomponents/webcomponentsjs@^1.0.7":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
@@ -877,7 +1422,17 @@
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.1.tgz#7baadec56ed2fd79b94ddfd509132d8c0c295c5c"
integrity sha512-7jxBb+KoWncKb/JGFyTY40PjV4yRx2zd35ZLuvRP+6WndJDL7X32ZIZ7bN3sSQIl+NzJkCo7chfXJyzn+6WZaQ==
-accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+"@webcomponents/webcomponentsjs@^2.4.0":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.3.tgz#384f4f6d54563ba465fb4df21fe89e78a76fc530"
+ integrity sha512-cV4+sAmshf8ysU2USutrSRYQkJzEYKHsRCGa0CkMElGpG5747VHtkfsW3NdVIBV/m2MDKXTDydT4lkrysH7IFA==
+
+abortcontroller-polyfill@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.4.0.tgz#0d5eb58e522a461774af8086414f68e1dda7a6c4"
+ integrity sha512-3ZFfCRfDzx3GFjO6RAkYx81lPGpUS20ISxux9gLxuKnqafNcFQo59+IoZqpO2WvQlyc287B62HDnDdNYRmlvWA==
+
+accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@@ -983,11 +1538,19 @@
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
-any-promise@^1.0.0:
+any-promise@^1.0.0, any-promise@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
+anymatch@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+ integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
append-field@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
@@ -1063,6 +1626,11 @@
resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
+array-back@^4.0.0, array-back@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.1.tgz#9b80312935a52062e1a233a9c7abeb5481b30e90"
+ integrity sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==
+
array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -1088,6 +1656,11 @@
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
+arrify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -1224,6 +1797,16 @@
dependencies:
object.assign "^4.1.0"
+babel-plugin-istanbul@^5.1.4:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854"
+ integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ find-up "^3.0.0"
+ istanbul-lib-instrument "^3.3.0"
+ test-exclude "^5.2.3"
+
babel-plugin-minify-builtins@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b"
@@ -1456,6 +2039,11 @@
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+base64id@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
+ integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=
+
base64id@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
@@ -1488,6 +2076,11 @@
dependencies:
callsite "1.0.0"
+binary-extensions@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
+ integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
+
bl@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
@@ -1508,7 +2101,12 @@
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
-body-parser@1.19.0, body-parser@^1.17.2:
+bluebird@^3.3.0:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
+ integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
+
+body-parser@1.19.0, body-parser@^1.16.1, body-parser@^1.17.2:
version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
@@ -1581,6 +2179,13 @@
split-string "^3.0.2"
to-regex "^3.0.1"
+braces@^3.0.2, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
browser-capabilities@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/browser-capabilities/-/browser-capabilities-1.1.4.tgz#a6bd657a07a134532ad66c722b8949904478b973"
@@ -1599,6 +2204,25 @@
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
+browserslist-useragent@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/browserslist-useragent/-/browserslist-useragent-3.0.2.tgz#f0e209b2742baa5de0e451b52e678e8b4402617c"
+ integrity sha512-/UPzK9xZnk5mwwWx4wcuBKAKx/mD3MNY8sUuZ2NPqnr4RVFWZogX+8mOP0cQEYo8j78sHk0hiDNaVXZ1U3hM9A==
+ dependencies:
+ browserslist "^4.6.6"
+ semver "^6.3.0"
+ useragent "^2.3.0"
+
+browserslist@^4.0.0, browserslist@^4.6.6, browserslist@^4.8.3, browserslist@^4.9.1:
+ version "4.11.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.1.tgz#92f855ee88d6e050e7e7311d987992014f1a1f1b"
+ integrity sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==
+ dependencies:
+ caniuse-lite "^1.0.30001038"
+ electron-to-chromium "^1.3.390"
+ node-releases "^1.1.53"
+ pkg-up "^2.0.0"
+
browserstack@^1.2.0:
version "1.5.3"
resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
@@ -1606,11 +2230,29 @@
dependencies:
https-proxy-agent "^2.2.1"
+buffer-alloc-unsafe@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
+ integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
+
+buffer-alloc@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
+ integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
+ dependencies:
+ buffer-alloc-unsafe "^1.1.0"
+ buffer-fill "^1.0.0"
+
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
+buffer-fill@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
+ integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
+
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@@ -1624,6 +2266,11 @@
base64-js "^1.0.2"
ieee754 "^1.1.4"
+builtin-modules@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
+ integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
+
busboy@^0.2.11:
version "0.2.14"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
@@ -1637,7 +2284,7 @@
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
-bytes@3.1.0:
+bytes@3.1.0, bytes@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
@@ -1657,12 +2304,20 @@
union-value "^1.0.0"
unset-value "^1.0.0"
+cache-content-type@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c"
+ integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==
+ dependencies:
+ mime-types "^2.1.18"
+ ylru "^1.2.0"
+
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
-camel-case@3.0.x:
+camel-case@3.0.x, camel-case@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
@@ -1688,7 +2343,7 @@
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
-camelcase@^5.0.0:
+camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
@@ -1700,6 +2355,21 @@
dependencies:
"@types/node" "^4.0.30"
+caniuse-api@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
+ integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
+ dependencies:
+ browserslist "^4.0.0"
+ caniuse-lite "^1.0.0"
+ lodash.memoize "^4.1.2"
+ lodash.uniq "^4.5.0"
+
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001033, caniuse-lite@^1.0.30001038:
+ version "1.0.30001038"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz#44da3cbca2ab6cb6aa83d1be5d324e17f141caff"
+ integrity sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==
+
capture-stack-trace@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
@@ -1742,7 +2412,7 @@
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1770,6 +2440,36 @@
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
+chokidar@3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6"
+ integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==
+ dependencies:
+ anymatch "~3.1.1"
+ braces "~3.0.2"
+ glob-parent "~5.1.0"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.2.0"
+ optionalDependencies:
+ fsevents "~2.1.1"
+
+chokidar@^3.0.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
+ integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
+ dependencies:
+ anymatch "~3.1.1"
+ braces "~3.0.2"
+ glob-parent "~5.1.0"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.3.0"
+ optionalDependencies:
+ fsevents "~2.1.2"
+
ci-info@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
@@ -1792,6 +2492,13 @@
dependencies:
source-map "~0.6.0"
+clean-css@^4.2.1:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
+ integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
+ dependencies:
+ source-map "~0.6.0"
+
cleankill@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/cleankill/-/cleankill-2.0.0.tgz#59830dfc8b411d53dc72ad09d45a78ea33161a91"
@@ -1821,11 +2528,16 @@
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
-clone@^2.0.0, clone@^2.1.0:
+clone@^2.0.0, clone@^2.1.0, clone@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@@ -1872,7 +2584,7 @@
resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
-colors@^1.2.1:
+colors@^1.1.0, colors@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
@@ -1912,6 +2624,16 @@
table-layout "^0.4.3"
typical "^2.6.1"
+command-line-usage@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.0.tgz#f28376a3da3361ff3d36cfd31c3c22c9a64c7cb6"
+ integrity sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==
+ dependencies:
+ array-back "^4.0.0"
+ chalk "^2.4.2"
+ table-layout "^1.0.0"
+ typical "^5.2.0"
+
commander@2.17.x:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
@@ -1924,7 +2646,7 @@
dependencies:
graceful-readlink ">= 1.0.0"
-commander@^2.19.0:
+commander@^2.19.0, commander@^2.20.0, commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -1964,7 +2686,7 @@
normalize-path "^3.0.0"
readable-stream "^2.3.6"
-compressible@~2.0.16:
+compressible@^2.0.0, compressible@~2.0.16:
version "2.0.18"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
@@ -2011,14 +2733,24 @@
write-file-atomic "^2.0.0"
xdg-basedir "^3.0.0"
-content-disposition@0.5.3:
+connect@^3.6.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8"
+ integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==
+ dependencies:
+ debug "2.6.9"
+ finalhandler "1.1.2"
+ parseurl "~1.3.3"
+ utils-merge "1.0.1"
+
+content-disposition@0.5.3, content-disposition@~0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
dependencies:
safe-buffer "5.1.2"
-content-type@^1.0.2, content-type@~1.0.4:
+content-type@^1.0.2, content-type@^1.0.4, content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
@@ -2045,11 +2777,32 @@
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookies@~0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90"
+ integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==
+ dependencies:
+ depd "~2.0.0"
+ keygrip "~1.1.0"
+
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+core-js-bundle@^3.6.0:
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.6.4.tgz#d4e098323c035f4a1b61f00db0b8def04c243920"
+ integrity sha512-qDHS3GbIEs5dZaBiCVhhtCoF79KU/ek0w+H7zfJf9RuGN0GiKfxHZfAtDy4zFtQ6X00t7Wvvr3wHzMj+/IgbPg==
+
+core-js-compat@^3.6.2:
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17"
+ integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==
+ dependencies:
+ browserslist "^4.8.3"
+ semver "7.0.0"
+
core-js@^2.4.0:
version "2.6.11"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
@@ -2143,6 +2896,11 @@
dependencies:
array-find-index "^1.0.1"
+custom-event@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
+ integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=
+
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -2150,6 +2908,16 @@
dependencies:
assert-plus "^1.0.0"
+date-format@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf"
+ integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==
+
+debounce@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
+ integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==
+
debug@2.6.8:
version "2.6.8"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
@@ -2164,7 +2932,7 @@
dependencies:
ms "2.0.0"
-debug@3.2.6, debug@^3.0.0, debug@^3.1.0:
+debug@3.2.6, debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -2209,11 +2977,21 @@
dependencies:
type-detect "^4.0.0"
+deep-equal@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
+ integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
+
deep-extend@^0.6.0, deep-extend@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+deepmerge@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.3.0.tgz#d3c47fd6f3a93d517b14426b0628a17b0125f5f7"
+ integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==
+
define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -2248,12 +3026,22 @@
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-depd@~1.1.2:
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+depd@^1.1.2, depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-destroy@~1.0.4:
+depd@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+destroy@^1.0.4, destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
@@ -2275,6 +3063,11 @@
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
+di@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
+ integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=
+
diagnostics@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
@@ -2309,6 +3102,16 @@
dependencies:
esutils "^2.0.2"
+dom-serialize@^2.2.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
+ integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=
+ dependencies:
+ custom-event "~1.0.0"
+ ent "~2.2.0"
+ extend "^3.0.0"
+ void-elements "^2.0.0"
+
dom-urls@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
@@ -2354,6 +3157,11 @@
readable-stream "^2.0.0"
stream-shift "^1.0.0"
+dynamic-import-polyfill@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/dynamic-import-polyfill/-/dynamic-import-polyfill-0.1.1.tgz#e1f9eb1876ee242bd56572f8ed4df768e143083f"
+ integrity sha512-m953zv0w5oDagTItWm6Auhmk/pY7EiejaqiVbnzSS3HIjh1FCUeK7WzuaVtWPNs58A+/xpIE+/dVk6pKsrua8g==
+
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
@@ -2367,6 +3175,11 @@
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+electron-to-chromium@^1.3.390:
+ version "1.3.392"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz#280ab4f7a3ae47419cfabb15dbfc1567be7f1111"
+ integrity sha512-/hsgeVdReDsyTBE0aU9FRdh1wnNPrX3xlz3t61F+CJPOT+Umfi9DXHsCX85TEgWZQqlow0Rw44/4/jbU2Sqgkg==
+
emitter-component@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
@@ -2384,18 +3197,35 @@
dependencies:
env-variable "0.0.x"
-encodeurl@~1.0.2:
+encodeurl@^1.0.2, encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-end-of-stream@^1.0.0, end-of-stream@^1.4.1:
+end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
+engine.io-client@~3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36"
+ integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==
+ dependencies:
+ component-emitter "1.2.1"
+ component-inherit "0.0.3"
+ debug "~3.1.0"
+ engine.io-parser "~2.1.1"
+ has-cors "1.1.0"
+ indexof "0.0.1"
+ parseqs "0.0.5"
+ parseuri "0.0.5"
+ ws "~3.3.1"
+ xmlhttprequest-ssl "~1.5.4"
+ yeast "0.1.2"
+
engine.io-client@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
@@ -2413,6 +3243,17 @@
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
+engine.io-parser@~2.1.0, engine.io-parser@~2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6"
+ integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==
+ dependencies:
+ after "0.8.2"
+ arraybuffer.slice "~0.0.7"
+ base64-arraybuffer "0.1.5"
+ blob "0.0.5"
+ has-binary2 "~1.0.2"
+
engine.io-parser@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
@@ -2424,6 +3265,18 @@
blob "0.0.5"
has-binary2 "~1.0.2"
+engine.io@~3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2"
+ integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==
+ dependencies:
+ accepts "~1.3.4"
+ base64id "1.0.0"
+ cookie "0.3.1"
+ debug "~3.1.0"
+ engine.io-parser "~2.1.0"
+ ws "~3.3.1"
+
engine.io@~3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
@@ -2436,18 +3289,28 @@
engine.io-parser "~2.2.0"
ws "^7.1.2"
+ent@~2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
+ integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0=
+
env-variable@0.0.x:
version "0.0.5"
resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
-error-ex@^1.2.0:
+error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
+error-inject@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37"
+ integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=
+
es-abstract@^1.17.0-next.1:
version "1.17.4"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
@@ -2465,6 +3328,67 @@
string.prototype.trimleft "^2.1.1"
string.prototype.trimright "^2.1.1"
+es-dev-server@^1.46.0:
+ version "1.46.0"
+ resolved "https://registry.yarnpkg.com/es-dev-server/-/es-dev-server-1.46.0.tgz#6fa8615604d8bfaa6a181f3bfb8b62d9f4b3dd81"
+ integrity sha512-+6RDz/YeBEkEHcf84I2pS+JYY1ov3d24JAda8hVMFQtpI21+G4/t0YA3lZSIYlPZ6AIoTgmb/+pKQh6JzmOUVA==
+ dependencies:
+ "@babel/core" "^7.9.0"
+ "@babel/plugin-proposal-dynamic-import" "^7.8.3"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-proposal-optional-chaining" "^7.9.0"
+ "@babel/plugin-syntax-class-properties" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-transform-template-literals" "^7.8.3"
+ "@babel/preset-env" "^7.9.0"
+ "@open-wc/building-utils" "^2.16.1"
+ "@rollup/plugin-node-resolve" "^6.1.0"
+ "@rollup/pluginutils" "^3.0.0"
+ "@types/minimatch" "^3.0.3"
+ browserslist "^4.9.1"
+ browserslist-useragent "^3.0.2"
+ builtin-modules "^3.1.0"
+ camelcase "^5.3.1"
+ caniuse-api "^3.0.0"
+ caniuse-lite "^1.0.30001033"
+ chokidar "^3.0.0"
+ command-line-args "^5.0.2"
+ command-line-usage "^6.1.0"
+ debounce "^1.2.0"
+ deepmerge "^3.2.0"
+ es-module-lexer "^0.3.13"
+ get-stream "^5.1.0"
+ is-stream "^2.0.0"
+ isbinaryfile "^4.0.2"
+ koa "^2.7.0"
+ koa-compress "^3.0.0"
+ koa-etag "^3.0.0"
+ koa-static "^5.0.0"
+ lru-cache "^5.1.1"
+ minimatch "^3.0.4"
+ opn "^5.4.0"
+ parse5 "^5.1.1"
+ path-is-inside "^1.0.2"
+ polyfills-loader "^1.5.2"
+ portfinder "^1.0.21"
+ strip-ansi "^5.2.0"
+ systemjs "^4.0.0"
+ useragent "^2.3.0"
+ whatwg-url "^7.0.0"
+
+es-module-lexer@^0.3.13:
+ version "0.3.17"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.17.tgz#a248dec2870934d9054420fead19db095ea21537"
+ integrity sha512-nwvMtzyEB6FhlyXBlV+BW2By3Vn2sUvlQBYP4LvdK8YpdbFQUOiBoeuB7/ip1+EbjmgNydkJ8+dIlyO09VP9BA==
+
+es-module-shims@^0.4.6:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/es-module-shims/-/es-module-shims-0.4.6.tgz#5decb313d52e5c62f6c19ed7e664ee9d66317d8a"
+ integrity sha512-EzVhnLyA/zvmGrAy2RU8m9xpxX7u2yb2by1GZH80SHF6lakG21YAm3Vo56KsLIXaIjT9QabqjYpQU1S5FkM8+Q==
+
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@@ -2514,12 +3438,17 @@
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+estree-walker@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
+ integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-etag@~1.8.1:
+etag@^1.3.0, etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
@@ -2716,7 +3645,14 @@
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
-finalhandler@~1.1.2:
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+finalhandler@1.1.2, finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
@@ -2758,6 +3694,13 @@
path-exists "^2.0.0"
pinkie-promise "^2.0.0"
+find-up@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+ integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
+ dependencies:
+ locate-path "^2.0.0"
+
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@@ -2780,6 +3723,11 @@
dependencies:
is-buffer "~2.0.3"
+flatted@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
+ integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
+
follow-redirects@^1.0.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
@@ -2849,7 +3797,7 @@
resolved "https://registry.yarnpkg.com/freeport/-/freeport-1.0.5.tgz#255e8ab84170c33ba85d990e821ae5f4a1a9bc5d"
integrity sha1-JV6KuEFwwzuoXZkOghrl9KGpvF0=
-fresh@0.5.2:
+fresh@0.5.2, fresh@~0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
@@ -2859,11 +3807,25 @@
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+fs-extra@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+fsevents@~2.1.1, fsevents@~2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
+ integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -2894,6 +3856,13 @@
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+get-stream@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
+ integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
+ dependencies:
+ pump "^3.0.0"
+
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -2929,6 +3898,13 @@
is-glob "^3.1.0"
path-dirname "^1.0.0"
+glob-parent@~5.1.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
+ integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
+ dependencies:
+ is-glob "^4.0.1"
+
glob-stream@^5.3.2:
version "5.3.5"
resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
@@ -3044,7 +4020,7 @@
unzip-response "^2.0.1"
url-parse-lax "^1.0.0"
-graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.0:
+graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
@@ -3101,7 +4077,7 @@
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-har-validator@~5.1.0:
+har-validator@~5.1.0, har-validator@~5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
@@ -3191,7 +4167,7 @@
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
-he@1.2.0, he@1.2.x:
+he@1.2.0, he@1.2.x, he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@@ -3231,6 +4207,27 @@
relateurl "0.2.x"
uglify-js "3.4.x"
+html-minifier@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
+ integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==
+ dependencies:
+ camel-case "^3.0.0"
+ clean-css "^4.2.1"
+ commander "^2.19.0"
+ he "^1.2.0"
+ param-case "^2.1.1"
+ relateurl "^0.2.7"
+ uglify-js "^3.5.1"
+
+http-assert@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.4.1.tgz#c5f725d677aa7e873ef736199b89686cceb37878"
+ integrity sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==
+ dependencies:
+ deep-equal "~1.0.1"
+ http-errors "~1.7.2"
+
http-deceiver@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@@ -3247,17 +4244,7 @@
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
-http-errors@~1.6.2:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
- integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.0"
- statuses ">= 1.4.0 < 2"
-
-http-errors@~1.7.2:
+http-errors@^1.6.3, http-errors@~1.7.2:
version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
@@ -3268,6 +4255,16 @@
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
+http-errors@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
http-proxy-middleware@^0.17.2:
version "0.17.4"
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833"
@@ -3278,7 +4275,7 @@
lodash "^4.17.2"
micromatch "^2.3.11"
-http-proxy@^1.16.2:
+http-proxy@^1.13.0, http-proxy@^1.16.2:
version "1.18.0"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
@@ -3374,7 +4371,12 @@
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-invariant@^2.2.2:
+intersection-observer@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9"
+ integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==
+
+invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -3415,6 +4417,13 @@
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
is-buffer@^1.1.5, is-buffer@~1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -3503,7 +4512,7 @@
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
-is-extglob@^2.1.0:
+is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
@@ -3539,6 +4548,13 @@
dependencies:
is-extglob "^2.1.0"
+is-glob@^4.0.1, is-glob@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+ integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+ dependencies:
+ is-extglob "^2.1.1"
+
is-installed-globally@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
@@ -3547,6 +4563,11 @@
global-dirs "^0.1.0"
is-path-inside "^1.0.0"
+is-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+ integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
+
is-npm@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
@@ -3571,6 +4592,11 @@
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
is-obj@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
@@ -3622,6 +4648,11 @@
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+
is-symbol@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -3649,6 +4680,11 @@
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+is-wsl@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
+ integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
+
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
@@ -3664,6 +4700,18 @@
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
+isbinaryfile@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
+ integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==
+ dependencies:
+ buffer-alloc "^1.2.0"
+
+isbinaryfile@^4.0.2:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.5.tgz#7193454fdd7fc0b12855c36c48d4ac7368fa3ec9"
+ integrity sha512-Jvz0gpTh1AILHMCBUyqq7xv1ZOQrxTDwyp1/QUq1xFpOBvp4AH5uEobPePJht8KnBGqQIH7We6OR73mXsjG0cA==
+
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -3686,6 +4734,24 @@
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+istanbul-lib-coverage@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
+ integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==
+
+istanbul-lib-instrument@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630"
+ integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==
+ dependencies:
+ "@babel/generator" "^7.4.0"
+ "@babel/parser" "^7.4.3"
+ "@babel/template" "^7.4.0"
+ "@babel/traverse" "^7.4.3"
+ "@babel/types" "^7.4.0"
+ istanbul-lib-coverage "^2.0.5"
+ semver "^6.0.0"
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -3724,6 +4790,11 @@
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+json-parse-better-errors@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+ integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -3756,6 +4827,20 @@
dependencies:
minimist "^1.2.0"
+json5@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e"
+ integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==
+ dependencies:
+ minimist "^1.2.5"
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
jsonschema@^1.1.0, jsonschema@^1.1.1:
version "1.2.5"
resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61"
@@ -3771,6 +4856,68 @@
json-schema "0.2.3"
verror "1.10.0"
+karma-chrome-launcher@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738"
+ integrity sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==
+ dependencies:
+ which "^1.2.1"
+
+karma-mocha-reporter@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz#15120095e8ed819186e47a0b012f3cd741895560"
+ integrity sha1-FRIAlejtgZGG5HoLAS8810GJVWA=
+ dependencies:
+ chalk "^2.1.0"
+ log-symbols "^2.1.0"
+ strip-ansi "^4.0.0"
+
+karma-mocha@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d"
+ integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==
+ dependencies:
+ minimist "^1.2.3"
+
+karma@^4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/karma/-/karma-4.4.1.tgz#6d9aaab037a31136dc074002620ee11e8c2e32ab"
+ integrity sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==
+ dependencies:
+ bluebird "^3.3.0"
+ body-parser "^1.16.1"
+ braces "^3.0.2"
+ chokidar "^3.0.0"
+ colors "^1.1.0"
+ connect "^3.6.0"
+ di "^0.0.1"
+ dom-serialize "^2.2.0"
+ flatted "^2.0.0"
+ glob "^7.1.1"
+ graceful-fs "^4.1.2"
+ http-proxy "^1.13.0"
+ isbinaryfile "^3.0.0"
+ lodash "^4.17.14"
+ log4js "^4.0.0"
+ mime "^2.3.1"
+ minimatch "^3.0.2"
+ optimist "^0.6.1"
+ qjobs "^1.1.4"
+ range-parser "^1.2.0"
+ rimraf "^2.6.0"
+ safe-buffer "^5.0.1"
+ socket.io "2.1.1"
+ source-map "^0.6.1"
+ tmp "0.0.33"
+ useragent "2.3.0"
+
+keygrip@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
+ integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==
+ dependencies:
+ tsscmp "1.0.6"
+
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
@@ -3795,6 +4942,97 @@
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+koa-compose@^3.0.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7"
+ integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=
+ dependencies:
+ any-promise "^1.1.0"
+
+koa-compose@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877"
+ integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==
+
+koa-compress@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/koa-compress/-/koa-compress-3.0.0.tgz#3194059c215cbc24e59bbc84c2c7453a4c88564f"
+ integrity sha512-xol+LkNB1mozKJkB5Kj6nYXbJXhkLkZlXl9BsGBPjujVfZ8MsIXwU4GHRTT7TlSfUcl2DU3JtC+j6wOWcovfuQ==
+ dependencies:
+ bytes "^3.0.0"
+ compressible "^2.0.0"
+ koa-is-json "^1.0.0"
+ statuses "^1.0.0"
+
+koa-convert@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0"
+ integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=
+ dependencies:
+ co "^4.6.0"
+ koa-compose "^3.0.0"
+
+koa-etag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/koa-etag/-/koa-etag-3.0.0.tgz#9ef7382ddd5a82ab0deb153415c915836f771d3f"
+ integrity sha1-nvc4Ld1agqsN6xU0FckVg293HT8=
+ dependencies:
+ etag "^1.3.0"
+ mz "^2.1.0"
+
+koa-is-json@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
+ integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=
+
+koa-send@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb"
+ integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==
+ dependencies:
+ debug "^3.1.0"
+ http-errors "^1.6.3"
+ mz "^2.7.0"
+ resolve-path "^1.4.0"
+
+koa-static@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943"
+ integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==
+ dependencies:
+ debug "^3.1.0"
+ koa-send "^5.0.0"
+
+koa@^2.7.0:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/koa/-/koa-2.11.0.tgz#fe5a51c46f566d27632dd5dc8fd5d7dd44f935a4"
+ integrity sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA==
+ dependencies:
+ accepts "^1.3.5"
+ cache-content-type "^1.0.0"
+ content-disposition "~0.5.2"
+ content-type "^1.0.4"
+ cookies "~0.8.0"
+ debug "~3.1.0"
+ delegates "^1.0.0"
+ depd "^1.1.2"
+ destroy "^1.0.4"
+ encodeurl "^1.0.2"
+ error-inject "^1.0.0"
+ escape-html "^1.0.3"
+ fresh "~0.5.2"
+ http-assert "^1.3.0"
+ http-errors "^1.6.3"
+ is-generator-function "^1.0.7"
+ koa-compose "^4.1.0"
+ koa-convert "^1.2.0"
+ on-finished "^2.3.0"
+ only "~0.0.2"
+ parseurl "^1.3.2"
+ statuses "^1.5.0"
+ type-is "^1.6.16"
+ vary "^1.1.2"
+
kuler@1.0.x:
version "1.0.1"
resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
@@ -3830,6 +5068,18 @@
dependencies:
readable-stream "^2.0.5"
+leven@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+ integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
+levenary@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77"
+ integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==
+ dependencies:
+ leven "^3.1.0"
+
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -3841,6 +5091,24 @@
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
+load-json-file@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
+ integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^4.0.0"
+ pify "^3.0.0"
+ strip-bom "^3.0.0"
+
+locate-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
+ dependencies:
+ p-locate "^2.0.0"
+ path-exists "^3.0.0"
+
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@@ -3940,6 +5208,11 @@
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
+lodash.memoize@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+ integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
+
lodash.padend@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
@@ -3970,6 +5243,11 @@
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
+lodash.uniq@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+ integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
lodash@^3.0.0, lodash@^3.10.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
@@ -3980,13 +5258,31 @@
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
-log-symbols@2.2.0:
+log-symbols@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
+ integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==
+ dependencies:
+ chalk "^2.4.2"
+
+log-symbols@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
dependencies:
chalk "^2.0.1"
+log4js@^4.0.0:
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.5.1.tgz#e543625e97d9e6f3e6e7c9fc196dd6ab2cae30b5"
+ integrity sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==
+ dependencies:
+ date-format "^2.0.0"
+ debug "^4.1.1"
+ flatted "^2.0.0"
+ rfdc "^1.1.4"
+ streamroller "^1.0.6"
+
logform@^1.9.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e"
@@ -4044,7 +5340,7 @@
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
-lru-cache@^4.0.1, lru-cache@^4.0.2:
+lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.0.2:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
@@ -4052,6 +5348,13 @@
pseudomap "^1.0.2"
yallist "^2.1.2"
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
magic-string@^0.22.4:
version "0.22.5"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
@@ -4185,7 +5488,7 @@
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
-mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
+mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.26"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
@@ -4236,6 +5539,11 @@
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+minimist@^1.2.3, minimist@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
@@ -4256,6 +5564,13 @@
dependencies:
minimist "0.0.8"
+mkdirp@0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c"
+ integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==
+ dependencies:
+ minimist "^1.2.5"
+
mocha@^3.4.2:
version "3.5.3"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d"
@@ -4274,13 +5589,14 @@
mkdirp "0.5.1"
supports-color "3.1.2"
-mocha@^6.2.2:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.2.tgz#5d8987e28940caf8957a7d7664b910dc5b2fea20"
- integrity sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==
+mocha@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441"
+ integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==
dependencies:
ansi-colors "3.2.3"
browser-stdout "1.3.1"
+ chokidar "3.3.0"
debug "3.2.6"
diff "3.5.0"
escape-string-regexp "1.0.5"
@@ -4289,18 +5605,18 @@
growl "1.10.5"
he "1.2.0"
js-yaml "3.13.1"
- log-symbols "2.2.0"
+ log-symbols "3.0.0"
minimatch "3.0.4"
- mkdirp "0.5.1"
+ mkdirp "0.5.3"
ms "2.1.1"
- node-environment-flags "1.0.5"
+ node-environment-flags "1.0.6"
object.assign "4.1.0"
strip-json-comments "2.0.1"
supports-color "6.0.0"
which "1.3.1"
wide-align "1.1.3"
- yargs "13.3.0"
- yargs-parser "13.1.1"
+ yargs "13.3.2"
+ yargs-parser "13.1.2"
yargs-unparser "1.6.0"
mout@^1.0.0:
@@ -4345,7 +5661,7 @@
duplexer2 "^0.1.2"
object-assign "^4.1.0"
-mz@^2.4.0, mz@^2.6.0:
+mz@^2.1.0, mz@^2.4.0, mz@^2.6.0, mz@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
@@ -4393,14 +5709,24 @@
dependencies:
lower-case "^1.1.1"
-node-environment-flags@1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
- integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
+node-environment-flags@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088"
+ integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==
dependencies:
object.getownpropertydescriptors "^2.0.3"
semver "^5.7.0"
+node-fetch@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+ integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
+node-releases@^1.1.53:
+ version "1.1.53"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4"
+ integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==
+
nomnom@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
@@ -4426,7 +5752,7 @@
dependencies:
remove-trailing-separator "^1.0.1"
-normalize-path@^3.0.0:
+normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -4544,7 +5870,7 @@
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
-once@^1.3.0, once@^1.4.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -4556,6 +5882,11 @@
resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+only@~0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4"
+ integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=
+
opn@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a"
@@ -4563,6 +5894,13 @@
dependencies:
object-assign "^4.0.1"
+opn@^5.4.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
+ integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
+ dependencies:
+ is-wsl "^1.1.0"
+
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
@@ -4584,7 +5922,7 @@
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
@@ -4602,6 +5940,13 @@
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+p-limit@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
+ dependencies:
+ p-try "^1.0.0"
+
p-limit@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
@@ -4609,6 +5954,13 @@
dependencies:
p-try "^2.0.0"
+p-locate@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+ integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
+ dependencies:
+ p-limit "^1.1.0"
+
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -4616,6 +5968,11 @@
dependencies:
p-limit "^2.0.0"
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+ integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
+
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -4631,7 +5988,7 @@
registry-url "^3.0.3"
semver "^5.1.0"
-param-case@2.1.x:
+param-case@2.1.x, param-case@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
@@ -4655,6 +6012,14 @@
dependencies:
error-ex "^1.2.0"
+parse-json@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+ integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
+ dependencies:
+ error-ex "^1.3.1"
+ json-parse-better-errors "^1.0.1"
+
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@@ -4665,6 +6030,11 @@
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
+parse5@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
+ integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
+
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
@@ -4679,7 +6049,7 @@
dependencies:
better-assert "~1.0.0"
-parseurl@~1.3.3:
+parseurl@^1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
@@ -4706,7 +6076,7 @@
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
-path-is-absolute@^1.0.0:
+path-is-absolute@1.0.1, path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
@@ -4747,6 +6117,13 @@
pify "^2.0.0"
pinkie-promise "^2.0.0"
+path-type@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+ integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
+ dependencies:
+ pify "^3.0.0"
+
pathval@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
@@ -4772,6 +6149,11 @@
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+picomatch@^2.0.4, picomatch@^2.0.7:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
+ integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
+
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -4794,6 +6176,13 @@
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+pkg-up@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
+ integrity sha1-yBmscoBZpGHKscOImivjxJoATX8=
+ dependencies:
+ find-up "^2.1.0"
+
plist@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
@@ -4812,6 +6201,28 @@
winston "^3.0.0"
winston-transport "^4.2.0"
+polyfills-loader@^1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/polyfills-loader/-/polyfills-loader-1.5.2.tgz#2fe63063da0d74aa69b611bd189d64ee443358c7"
+ integrity sha512-bcv8Id4Ylae0eSmnlMpKfba36TNr1Mh7uMGN4OEIspHLGR5/IBGSBteQp/NpbZ45T7UWQuTBvVJNQCS16E1N4A==
+ dependencies:
+ "@babel/core" "^7.9.0"
+ "@open-wc/building-utils" "^2.16.1"
+ "@webcomponents/webcomponentsjs" "^2.4.0"
+ abortcontroller-polyfill "^1.4.0"
+ core-js-bundle "^3.6.0"
+ deepmerge "^3.2.0"
+ dynamic-import-polyfill "^0.1.1"
+ es-module-shims "^0.4.6"
+ html-minifier "^4.0.0"
+ intersection-observer "^0.7.0"
+ parse5 "^5.1.1"
+ regenerator-runtime "^0.13.3"
+ resize-observer-polyfill "^1.5.1"
+ systemjs "^4.0.0"
+ terser "^4.6.4"
+ whatwg-fetch "^3.0.0"
+
polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.4.tgz#7d76356620a2328e8bc9e30e47069f9729260ca1"
@@ -5001,6 +6412,15 @@
send "^0.16.2"
spdy "^3.3.3"
+portfinder@^1.0.21:
+ version "1.0.25"
+ resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca"
+ integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==
+ dependencies:
+ async "^2.6.2"
+ debug "^3.1.1"
+ mkdirp "^0.5.1"
+
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
@@ -5021,7 +6441,7 @@
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
-private@^0.1.6:
+private@^0.1.6, private@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
@@ -5054,12 +6474,25 @@
resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
+psl@^1.1.28:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
+ integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-punycode@^2.1.0:
+punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
@@ -5069,6 +6502,11 @@
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
+qjobs@^1.1.4:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071"
+ integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==
+
qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
@@ -5088,7 +6526,7 @@
kind-of "^6.0.0"
math-random "^1.0.1"
-range-parser@~1.2.0, range-parser@~1.2.1:
+range-parser@^1.2.0, range-parser@~1.2.0, range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
@@ -5121,6 +6559,14 @@
find-up "^1.0.0"
read-pkg "^1.0.0"
+read-pkg-up@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
+ integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==
+ dependencies:
+ find-up "^3.0.0"
+ read-pkg "^3.0.0"
+
read-pkg@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
@@ -5130,6 +6576,15 @@
normalize-package-data "^2.3.2"
path-type "^1.0.0"
+read-pkg@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
+ integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
+ dependencies:
+ load-json-file "^4.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^3.0.0"
+
readable-stream@1.1.x:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@@ -5172,6 +6627,20 @@
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
+readdirp@~3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839"
+ integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==
+ dependencies:
+ picomatch "^2.0.4"
+
+readdirp@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
+ integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
+ dependencies:
+ picomatch "^2.0.7"
+
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -5185,6 +6654,11 @@
resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
+reduce-flatten@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27"
+ integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==
+
regenerate-unicode-properties@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
@@ -5192,6 +6666,13 @@
dependencies:
regenerate "^1.4.0"
+regenerate-unicode-properties@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
+ integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
+ dependencies:
+ regenerate "^1.4.0"
+
regenerate@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
@@ -5202,6 +6683,11 @@
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4:
+ version "0.13.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
+ integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+
regenerator-transform@^0.14.0:
version "0.14.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"
@@ -5209,6 +6695,14 @@
dependencies:
private "^0.1.6"
+regenerator-transform@^0.14.2:
+ version "0.14.4"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7"
+ integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==
+ dependencies:
+ "@babel/runtime" "^7.8.4"
+ private "^0.1.8"
+
regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
@@ -5236,6 +6730,18 @@
unicode-match-property-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript "^1.1.0"
+regexpu-core@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938"
+ integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==
+ dependencies:
+ regenerate "^1.4.0"
+ regenerate-unicode-properties "^8.2.0"
+ regjsgen "^0.5.1"
+ regjsparser "^0.6.4"
+ unicode-match-property-ecmascript "^1.0.4"
+ unicode-match-property-value-ecmascript "^1.2.0"
+
registry-auth-token@^3.0.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
@@ -5251,7 +6757,7 @@
dependencies:
rc "^1.0.1"
-regjsgen@^0.5.0:
+regjsgen@^0.5.0, regjsgen@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
@@ -5263,7 +6769,14 @@
dependencies:
jsesc "~0.5.0"
-relateurl@0.2.x:
+regjsparser@^0.6.4:
+ version "0.6.4"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272"
+ integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==
+ dependencies:
+ jsesc "~0.5.0"
+
+relateurl@0.2.x, relateurl@^0.2.7:
version "0.2.7"
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
@@ -5321,6 +6834,32 @@
tunnel-agent "^0.6.0"
uuid "^3.3.2"
+request@^2.88.0:
+ version "2.88.2"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
+ integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.3"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.5.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@@ -5341,6 +6880,11 @@
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+resize-observer-polyfill@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+ integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
resolve-dir@^1.0.0, resolve-dir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
@@ -5349,6 +6893,14 @@
expand-tilde "^2.0.0"
global-modules "^1.0.0"
+resolve-path@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7"
+ integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=
+ dependencies:
+ http-errors "~1.6.2"
+ path-is-absolute "1.0.1"
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -5361,12 +6913,24 @@
dependencies:
path-parse "^1.0.6"
+resolve@^1.11.1:
+ version "1.15.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
+ integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==
+ dependencies:
+ path-parse "^1.0.6"
+
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-rimraf@^2.5.4:
+rfdc@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2"
+ integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==
+
+rimraf@^2.5.4, rimraf@^2.6.0:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
@@ -5480,6 +7044,16 @@
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+semver@7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
+ integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
+
+semver@^6.0.0, semver@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+ integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@@ -5568,6 +7142,11 @@
resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+shady-css-scoped-element@^0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/shady-css-scoped-element/-/shady-css-scoped-element-0.0.2.tgz#c538fcfe2317e979cd02dfec533898b95b4ea8fe"
+ integrity sha512-Dqfl70x6JiwYDujd33ZTbtCK0t52E7+H2swdWQNSTzfsolSa6LJHnTpN4T9OpJJEq4bxuzHRLFO9RBcy/UfrMQ==
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -5656,6 +7235,26 @@
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
+socket.io-client@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f"
+ integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==
+ dependencies:
+ backo2 "1.0.2"
+ base64-arraybuffer "0.1.5"
+ component-bind "1.0.0"
+ component-emitter "1.2.1"
+ debug "~3.1.0"
+ engine.io-client "~3.2.0"
+ has-binary2 "~1.0.2"
+ has-cors "1.1.0"
+ indexof "0.0.1"
+ object-component "0.0.3"
+ parseqs "0.0.5"
+ parseuri "0.0.5"
+ socket.io-parser "~3.2.0"
+ to-array "0.1.4"
+
socket.io-client@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
@@ -5676,6 +7275,15 @@
socket.io-parser "~3.3.0"
to-array "0.1.4"
+socket.io-parser@~3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077"
+ integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==
+ dependencies:
+ component-emitter "1.2.1"
+ debug "~3.1.0"
+ isarray "2.0.1"
+
socket.io-parser@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
@@ -5694,6 +7302,18 @@
debug "~4.1.0"
isarray "2.0.1"
+socket.io@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980"
+ integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==
+ dependencies:
+ debug "~3.1.0"
+ engine.io "~3.2.0"
+ has-binary2 "~1.0.2"
+ socket.io-adapter "~1.1.0"
+ socket.io-client "2.1.1"
+ socket.io-parser "~3.2.0"
+
socket.io@^2.0.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
@@ -5717,6 +7337,14 @@
source-map-url "^0.4.0"
urix "^0.1.0"
+source-map-support@~0.5.12:
+ version "0.5.16"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
+ integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -5727,7 +7355,7 @@
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -5836,7 +7464,7 @@
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.0.0, statuses@^1.5.0, statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
@@ -5858,6 +7486,17 @@
dependencies:
emitter-component "^1.1.1"
+streamroller@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.6.tgz#8167d8496ed9f19f05ee4b158d9611321b8cacd9"
+ integrity sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==
+ dependencies:
+ async "^2.6.2"
+ date-format "^2.0.0"
+ debug "^3.2.6"
+ fs-extra "^7.0.1"
+ lodash "^4.17.14"
+
streamsearch@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
@@ -5956,6 +7595,11 @@
dependencies:
is-utf8 "^0.2.0"
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
@@ -6028,6 +7672,11 @@
path-to-regexp "^1.0.1"
serviceworker-cache-polyfill "^4.0.0"
+systemjs@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-4.1.1.tgz#c90061456f9707478d487b47f3b92b9896032889"
+ integrity sha512-/0x3bcMrl1pxDCLw6sJWEKPVy0ZGEu7I0nItFSHxfPoDU2Lll6TUyB1wqltvbm7n5y5jVOoK4lei4oMpmW7XJQ==
+
table-layout@^0.4.3:
version "0.4.5"
resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.4.5.tgz#d906de6a25fa09c0c90d1d08ecd833ecedcb7378"
@@ -6039,6 +7688,16 @@
typical "^2.6.1"
wordwrapjs "^3.0.0"
+table-layout@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.1.tgz#8411181ee951278ad0638aea2f779a9ce42894f9"
+ integrity sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==
+ dependencies:
+ array-back "^4.0.1"
+ deep-extend "~0.6.0"
+ typical "^5.2.0"
+ wordwrapjs "^4.0.0"
+
tar-stream@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
@@ -6085,6 +7744,25 @@
merge-stream "^1.0.0"
through2 "^2.0.1"
+terser@^4.6.4:
+ version "4.6.10"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.10.tgz#90f5bd069ff456ddbc9503b18e52f9c493d3b7c2"
+ integrity sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA==
+ dependencies:
+ commander "^2.20.0"
+ source-map "~0.6.1"
+ source-map-support "~0.5.12"
+
+test-exclude@^5.2.3:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0"
+ integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==
+ dependencies:
+ glob "^7.1.3"
+ minimatch "^3.0.4"
+ read-pkg-up "^4.0.0"
+ require-main-filename "^2.0.0"
+
text-encoding@0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
@@ -6146,6 +7824,13 @@
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
+tmp@0.0.33, tmp@0.0.x:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
to-absolute-glob@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
@@ -6183,6 +7868,13 @@
is-number "^3.0.0"
repeat-string "^1.6.1"
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
@@ -6206,6 +7898,14 @@
psl "^1.1.24"
punycode "^1.4.1"
+tough-cookie@~2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
+ integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
+ dependencies:
+ psl "^1.1.28"
+ punycode "^2.1.1"
+
tr46@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
@@ -6228,6 +7928,11 @@
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
+tsscmp@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
+ integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==
+
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@@ -6255,7 +7960,7 @@
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
+type-is@^1.6.16, type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
@@ -6278,6 +7983,11 @@
resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
+typical@^5.0.0, typical@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"
+ integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==
+
ua-parser-js@^0.7.15:
version "0.7.21"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
@@ -6291,6 +8001,19 @@
commander "~2.19.0"
source-map "~0.6.1"
+uglify-js@^3.5.1:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.8.1.tgz#43bb15ce6f545eaa0a64c49fd29375ea09fa0f93"
+ integrity sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw==
+ dependencies:
+ commander "~2.20.3"
+ source-map "~0.6.1"
+
+ultron@~1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
+ integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==
+
underscore@^1.8.3:
version "1.9.2"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
@@ -6319,6 +8042,11 @@
resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+unicode-match-property-value-ecmascript@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
+ integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
+
unicode-property-aliases-ecmascript@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
@@ -6349,6 +8077,11 @@
dependencies:
crypto-random-string "^1.0.0"
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -6424,6 +8157,14 @@
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+useragent@2.3.0, useragent@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972"
+ integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==
+ dependencies:
+ lru-cache "4.1.x"
+ tmp "0.0.x"
+
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -6455,6 +8196,11 @@
resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
+valid-url@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200"
+ integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=
+
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -6468,7 +8214,7 @@
resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=
-vary@^1, vary@~1.1.2:
+vary@^1, vary@^1.1.2, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
@@ -6519,6 +8265,11 @@
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
+void-elements@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
+ integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+
vscode-uri@=1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
@@ -6631,6 +8382,11 @@
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+whatwg-fetch@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
+ integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
+
whatwg-url@^6.4.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
@@ -6640,12 +8396,21 @@
tr46 "^1.0.1"
webidl-conversions "^4.0.2"
+whatwg-url@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
+ integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
+ dependencies:
+ lodash.sortby "^4.7.0"
+ tr46 "^1.0.1"
+ webidl-conversions "^4.0.2"
+
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@1.3.1, which@^1.0.8, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+which@1.3.1, which@^1.0.8, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -6702,6 +8467,14 @@
reduce-flatten "^1.0.1"
typical "^2.6.1"
+wordwrapjs@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.0.tgz#9aa9394155993476e831ba8e59fb5795ebde6800"
+ integrity sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==
+ dependencies:
+ reduce-flatten "^2.0.0"
+ typical "^5.0.0"
+
wrap-ansi@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
@@ -6730,6 +8503,15 @@
resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
+ws@~3.3.1:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
+ integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==
+ dependencies:
+ async-limiter "~1.0.0"
+ safe-buffer "~5.1.0"
+ ultron "~1.1.0"
+
ws@~6.1.0:
version "6.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
@@ -6772,7 +8554,20 @@
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-yargs-parser@13.1.1, yargs-parser@^13.1.1:
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yargs-parser@13.1.2, yargs-parser@^13.1.2:
+ version "13.1.2"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
+ integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^13.1.1:
version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
@@ -6789,7 +8584,23 @@
lodash "^4.17.15"
yargs "^13.3.0"
-yargs@13.3.0, yargs@^13.3.0:
+yargs@13.3.2:
+ version "13.3.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
+ integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
+ dependencies:
+ cliui "^5.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^2.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^3.0.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^13.1.2"
+
+yargs@^13.3.0:
version "13.3.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==
@@ -6818,6 +8629,11 @@
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
+ylru@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"
+ integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==
+
zip-stream@^2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
diff --git a/tools/maven/gerrit-acceptance-framework_pom.xml b/tools/maven/gerrit-acceptance-framework_pom.xml
index 4240a9b..0f6f6d4 100644
--- a/tools/maven/gerrit-acceptance-framework_pom.xml
+++ b/tools/maven/gerrit-acceptance-framework_pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-acceptance-framework</artifactId>
- <version>3.2.0-SNAPSHOT</version>
+ <version>3.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Acceptance Test Framework</name>
<description>Framework for Gerrit's acceptance tests</description>
diff --git a/tools/maven/gerrit-extension-api_pom.xml b/tools/maven/gerrit-extension-api_pom.xml
index cf2b080..cb0f882 100644
--- a/tools/maven/gerrit-extension-api_pom.xml
+++ b/tools/maven/gerrit-extension-api_pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-extension-api</artifactId>
- <version>3.2.0-SNAPSHOT</version>
+ <version>3.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Extension API</name>
<description>API for Gerrit Extensions</description>
diff --git a/tools/maven/gerrit-plugin-api_pom.xml b/tools/maven/gerrit-plugin-api_pom.xml
index 7d3c4f0..e542b47 100644
--- a/tools/maven/gerrit-plugin-api_pom.xml
+++ b/tools/maven/gerrit-plugin-api_pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-plugin-api</artifactId>
- <version>3.2.0-SNAPSHOT</version>
+ <version>3.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Plugin API</name>
<description>API for Gerrit Plugins</description>
diff --git a/tools/maven/gerrit-war_pom.xml b/tools/maven/gerrit-war_pom.xml
index 9478283..4a69f2e 100644
--- a/tools/maven/gerrit-war_pom.xml
+++ b/tools/maven/gerrit-war_pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-war</artifactId>
- <version>3.2.0-SNAPSHOT</version>
+ <version>3.3.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Gerrit Code Review - WAR</name>
<description>Gerrit WAR</description>
diff --git a/version.bzl b/version.bzl
index fb1e5ca..78b286b 100644
--- a/version.bzl
+++ b/version.bzl
@@ -2,4 +2,4 @@
# Used by :api_install and :api_deploy targets
# when talking to the destination repository.
#
-GERRIT_VERSION = "3.2.0-SNAPSHOT"
+GERRIT_VERSION = "3.3.0-SNAPSHOT"