Merge "Implement 'inhastag' operator"
diff --git a/.bazelrc b/.bazelrc
index 6e26484..4d30086 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -11,6 +11,12 @@
# this flag here once flipped in Bazel again.
build --incompatible_strict_action_env
+build --announce_rc
+
+# Workaround Bazel worker crash (remove after upgrading to 4.1.0)
+# https://github.com/bazelbuild/bazel/issues/13333
+build --experimental_worker_multiplex=false
+
test --build_tests_only
test --test_output=errors
test --java_toolchain=//tools:error_prone_warnings_toolchain_java11
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index 9e3d70b..0575eb9 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -53,9 +53,10 @@
-b::
Name of the initial branch(es) in the newly created project.
Several branches can be specified on the command line.
- If several branches are specified then the first one becomes HEAD
- of the project. If none branches are specified then default value
- ('master') is used.
+ If several branches are specified then the first one becomes
+ link:project-configuration.html#default-branch[HEAD] of the project.
+ If none branches are specified then link:config-gerrit.html#gerrit.defaultBranch[host-level default]
+ is used.
--owner::
-o::
diff --git a/Documentation/concept-changes.txt b/Documentation/concept-changes.txt
index 6de787c..0444fab 100644
--- a/Documentation/concept-changes.txt
+++ b/Documentation/concept-changes.txt
@@ -104,6 +104,9 @@
Assigning a topic to a change can be done in the change screen or through a `git
push` command.
+For more information about using topics, see the user guide:
+link:cross-repository-changes.html[Submitting Changes Across Repositories by using Topics].
+
[[submit-strategies]]
== Submit strategies
diff --git a/Documentation/config-accounts.txt b/Documentation/config-accounts.txt
index c6d9fb4..8088b66 100644
--- a/Documentation/config-accounts.txt
+++ b/Documentation/config-accounts.txt
@@ -293,12 +293,12 @@
External IDs are stored as Git Notes in the `All-Users` repository. The
name of the notes branch is `refs/meta/external-ids`.
-As note key the SHA1 of the external ID key is used, for example the key
+As note key the SHA-1 of the external ID key is used, for example the key
for the external ID `username:jdoe` is `e0b751ae90ef039f320e097d7d212f490e933706`.
This ensures that an external ID is used only once (e.g. an external ID can
never be assigned to multiple accounts at a point in time).
-The following commands show how to find the SHA1 of an external ID:
+The following commands show how to find the SHA-1 of an external ID:
----
$ echo -n 'gerrit:jdoe' | shasum
@@ -310,7 +310,7 @@
[IMPORTANT]
If the external ID key is changed manually you must adapt the note key
-to the new SHA1, otherwise the external ID becomes inconsistent and is
+to the new SHA-1, otherwise the external ID becomes inconsistent and is
ignored by Gerrit.
The note content is a Git config file:
@@ -322,7 +322,7 @@
password = bcrypt:4:LCbmSBDivK/hhGVQMfkDpA==:XcWn0pKYSVU/UJgOvhidkEtmqCp6oKB7
----
-Once SHA1 of an external ID is known the following command can be used to
+Once SHA-1 of an external ID is known the following command can be used to
show the content of the note:
----
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 23720460..3ad4401 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -815,6 +815,7 @@
* `"groups"`: default is unlimited
* `"groups_byname"`: default is unlimited
* `"groups_byuuid"`: default is unlimited
+* `"groups_byuuid_persisted"`: default is `1g` (1 GiB of disk space)
* `"plugin_resources"`: default is 2m (2 MiB of memory)
+
@@ -1038,6 +1039,17 @@
External group membership obtained from LDAP is cached under
`"ldap_groups"`.
+cache `"groups_byuuid_persisted"`::
++
+Caches the basic group information of internal groups by group UUID,
+including the group owner, name, and description.
++
+This is the persisted version of `groups_byuuid` cache. The intention of this
+cache is to have an in-memory size of 0.
++
+External group membership obtained from LDAP is cached under
+`"ldap_groups"`.
+
cache `"groups_bymember"`::
+
Caches the groups which contain a specific member (account). If direct
@@ -2122,6 +2134,13 @@
+
Defaults to `All-Projects` if not set.
+[[gerrit.defaultBranch]]gerrit.defaultBranch::
++
+Name of the link:project-configuration.html#default-branch[default branch]
+to use on the project creation, if no other branches were specified in the input.
++
+Defaults to `refs/heads/master` if not set.
+
[[gerrit.allUsers]]gerrit.allUsers::
+
Name of the project in which meta data of all users is stored.
@@ -2197,11 +2216,21 @@
By default unset, as the HTTP daemon must be configured externally
by the system administrator, and might not even be running on the
same host as Gerrit.
-
++
+[[gerrit.installBatchModule]]gerrit.installBatchModule::
++
+Repeatable list of class name of additional Guice modules to load as
+override to the batchInjector's modules during the init phases.
+Classes are resolved using the primary Gerrit class loader, hence the
+class needs to be either declared in Gerrit or an additional JAR
+located under the `/lib` directory.
++
+By default unset.
++
[[gerrit.installDbModule]]gerrit.installDbModule::
+
Repeatable list of class name of additional Guice modules to load at
-Gerrit startup as part of the dbInjector and during the init phases.
+Gerrit startup as part of the dbInjector.
Classes are resolved using the primary Gerrit class loader, hence the
class needs to be either declared in Gerrit or an additional JAR
located under the `/lib` directory.
@@ -2211,7 +2240,7 @@
[[gerrit.installModule]]gerrit.installModule::
+
Repeatable list of class name of additional Guice modules to load at
-Gerrit startup as part of the sysInjector and during the init phases.
+Gerrit startup as part of the sysInjector.
Classes are resolved using the primary Gerrit class loader, hence the
class needs to be either declared in Gerrit or an additional JAR
located under the `/lib` directory.
@@ -2224,6 +2253,7 @@
installModule = com.googlesource.gerrit.libmodule.MyModule
installModule = com.example.abc.OurSpecialSauceModule
installDbModule = com.example.def.OurCustomProvider
+ installBatchModule = com.example.ghi.CustomBatchInitModule
----
[[gerrit.listProjectsFromIndex]]gerrit.listProjectsFromIndex::
@@ -2421,7 +2451,7 @@
at a specific commit when `gitweb.type` is set to `custom`.
+
Valid replacements are `${project}` for the project name in Gerrit
-and `${commit}` for the SHA1 hash for the commit.
+and `${commit}` for the SHA-1 hash for the commit.
[[gitweb.project]]gitweb.project::
+
@@ -2453,7 +2483,7 @@
is set to `custom`.
+
Valid replacements are `${project}` for the project name in Gerrit
-and `${commit}` for the SHA1 hash for the commit.
+and `${commit}` for the SHA-1 hash for the commit.
[[gitweb.file]]gitweb.file::
+
@@ -2462,7 +2492,7 @@
set to `custom`.
+
Valid replacements are `${project}` for the project name in Gerrit,
-`${file}` for the file name and `${commit}` for the SHA1 hash for
+`${file}` for the file name and `${commit}` for the SHA-1 hash for
the commit.
[[gitweb.filehistory]]gitweb.filehistory::
@@ -4166,7 +4196,7 @@
very CPU-heavy operation. For non public Gerrit-servers this check may
be overkill.
+
-Only disable this check if you trust the clients not to forge SHA1
+Only disable this check if you trust the clients not to forge SHA-1
references to access commits intended to be hidden from the user.
+
Default is true.
@@ -4807,6 +4837,16 @@
replicate = replication start
----
+[[ssh]]
+=== Section ssh
+
+[[ssh.clientImplementation]]ssh.clientImplementation::
++
+JCraft JSch client is supported in addition to Apache MINA SSH client.
+To use JSch client set the value to `JSCH`.
++
+By default, `APACHE`.
+
[[sshd]]
=== Section sshd
diff --git a/Documentation/config-groups.txt b/Documentation/config-groups.txt
index afabbfc..0917515 100644
--- a/Documentation/config-groups.txt
+++ b/Documentation/config-groups.txt
@@ -64,7 +64,7 @@
The format of this map is as follows:
-* keys are the normal SHA1 of the group name
+* keys are the normal SHA-1 of the group name
* values are blobs that look like
+
----
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index 56d26dc..b6184d7 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -353,7 +353,7 @@
If true, all scores for the label are copied forward when a new patch
set is uploaded that has the same parent tree, code delta, and commit
message as the previous patch set. This means that only the patch
-set SHA1 is different. This can be used to enable sticky
+set SHA-1 is different. This can be used to enable sticky
approvals, reducing turn-around for this special case.
It is recommended to leave this enabled for both Verified and
Code-Review labels.
diff --git a/Documentation/config-sso.txt b/Documentation/config-sso.txt
index 14399a3..37ab0c0 100644
--- a/Documentation/config-sso.txt
+++ b/Documentation/config-sso.txt
@@ -44,9 +44,9 @@
* `http://` -- trust all OpenID providers using the HTTP protocol
* `https://` -- trust all OpenID providers using the HTTPS protocol
-To trust only Yahoo!:
+To trust only Launchpad:
----
- git config --file $site_path/etc/gerrit.config auth.trustedOpenID https://me.yahoo.com
+ git config --file $site_path/etc/gerrit.config auth.trustedOpenID https://login.launchpad.net/+openid
----
=== Database Schema
diff --git a/Documentation/config-validation.txt b/Documentation/config-validation.txt
index cb953c1..56c9ecd 100644
--- a/Documentation/config-validation.txt
+++ b/Documentation/config-validation.txt
@@ -21,6 +21,14 @@
Out of the box, Gerrit includes a plugin that checks the length of the
subject and body lines of commit messages on uploaded commits.
+[plugin-push-options]]
+=== Plugin push options
+
+Plugins can register push options by implementing the `PluginPushOption`
+interface. If a plugin push option was specified it is available from
+the `CommitReceivedEvent` that is passed into `CommitValidationListener`.
+This way the plugin commit validation can be controlled by push options.
+
[[user-ref-operations-validation]]
== User ref operations validation
diff --git a/Documentation/cross-repository-changes.txt b/Documentation/cross-repository-changes.txt
new file mode 100644
index 0000000..53fd5cd
--- /dev/null
+++ b/Documentation/cross-repository-changes.txt
@@ -0,0 +1,254 @@
+:linkattrs:
+= Gerrit Code Review - Submitting Changes Across Repositories by using Topics
+
+== Goal
+
+This document describes how to propose and submit code changes across multiple
+Git repositories together in Gerrit.
+
+== When to Use
+
+Oftentimes, especially for larger code bases, code is split across multiple
+repositories. The Android operating system’s code base, for example, consists of
+https://android.googlesource.com/[hundreds] of separate repositories. When
+making a change, you might make code changes that span multiple repositories.
+For example, one repository could define an API which is used in another
+repository. Submitting these changes across these repositories separately could
+cause the build to break for other developers.
+
+Gerrit provides a mechanism called link:intro-user.html#topics[Topics] to submit
+changes together to prevent this problem.
+
+|===
+|NOTE: Usage of topics to submit multiple changes together requires your
+Gerrit host having
+link:config-gerrit.html#change.submitWholeTopic[config.submitWholeTopic] set to
+true. Ask your Gerrit administrator if you're not sure if this is enabled for
+your Gerrit instance.
+|===
+
+== What is a Topic?
+
+* A topic is a string that can be associated with a change.
+* Multiple changes can use that topic to be submitted at the same time (assuming
+ approvals, etc.).
+* Submitting a change with a topic causes all of the changes in the topic *to be
+ submitted together*
+ ** Topics that span only a single repository are guaranteed to be submitted
+ together
+ ** Topics that span multiple repositories simply triggers submission of all
+ changes. No other guarantees are given. Submission of all changes could
+ fail, so you could get a partial topic submission. This is very rare but
+ can happen in some of the following situations:
+ *** Storage layer failures. This is unlikely in single-master installation and
+ more likely with multi-master setups.
+ *** Race conditions. Concurrent submits to the same repository or concurrent
+ updates of the pending changes.
+
+Here are a few intricacies you should be aware of:
+
+1. Topics can only be used for changes within a single Gerrit instance. There is
+no builtin support for synchronizing with other Gerrit or Git hosting sites.
+
+2. A topic can be any string, and they are not namespaced in a Gerrit instance;
+there is a chance for collisions and inadvertently grouping changes together
+that weren’t meant to be grouped. This could even happen with changes you can’t
+see, leading to more confusion e.g. (change not submittable, but you can't see
+why it's not submittable.). We suggest prefixing topic strings with the author’s
+username e.g. “username-” to help avoid this.
+
+You can view the assigned topic from the change screen in Gerrit:
+
+image::images/cross-repository-changes-topic.png[width=600]
+
+=== Topic submission behavior
+* Submitting a topic will submit any dependent changes as well. For example,
+ an unsubmitted parent change will also be submitted, even if it isn’t in the
+ original topic.
+* A change with a topic is submittable when *all changes* in the topic are
+ submittable and *all of the changes’ dependent changes* (and their topics!)
+ are also submittable.
+* Gerrit calls the totality of these changes "Submitted Together", and they can
+be found with the
+ link:rest-api-changes.html#submitted-together[Submitted Together endpoint] or
+ on the change screen.
+
+image::images/cross-repository-changes-submitted-together.png[width=600]
+
+* A submission creates a unique submission ID
+ (link:rest-api-changes.html#change-info[`submission_id`]), which can be
+ used in Gerrit's search bar to find all the submitted changes for the
+ submission. This ID is relevant when <<reverting,reverting a submission>>.
+
+To better underestand this behavior, consider this following example.
+
+[[example_submission]]
+=== Example Submission
+
+image::images/cross-repository-changes-example.png[width=600]
+
+* Two repositories: A and B
+* Two changes in A: A1 and A2, where A2 is the child change.
+* Two changes in B: B1 and B2, where B2 is the child change.
+* Topic X contains change A1 and B1
+* Topic Y contains change A2 and B2
+
+Submission of A2 will submit all four of these changes because submission of A2
+submits all of topic Y as well as all dependent changes and their topics i.e. A1
+and topic X.
+
+Because of this, any submission is blocked until all four of these changes are
+submittable.
+
+|===
+| Important point: B1 can unexpectedly block the submission of A2!
+This kind of situation is hard to immediately grok: B1 isn't in the topic you're
+trying to submit, and it isn't a depnedent change of A2. If your topic isn’t
+submittable and you can’t figure out why, this might be a reason.
+|===
+
+== Submitting Changes Using Topics
+
+=== 1. *Associate the changes to a topic*
+
+The first step is to associate all the changes you want to be submitted together
+with the same topic. There are multiple ways to associate changes with a topic.
+
+==== From the command line
+You can set the topic name when uploading to Gerrit
+
+----
+$ git push origin HEAD:refs/heads/master -o topic=[YOUR_TOPIC_NAME]
+----
+
+*OR*
+
+----
+$ git push origin HEAD:refs/for/master%topic=[YOUR_TOPIC_NAME]
+----
+
+If you’re using https://source.android.com/setup/develop[repo] to upload a
+change to Android Gerrit, you can associate a topic via:
+
+----
+$ repo upload -o topic=[YOUR_TOPIC_NAME]
+----
+
+If you’re using
+https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools.html[depot_tools]
+to upload a change to Chromium Gerrit, you can associate a topic via:
+
+----
+$ git cl upload --topic=[YOUR_TOPIC_NAME]
+----
+
+==== From the UI
+
+If the change has already been created, you can add a topic from the change page
+by clicking ADD TOPIC, found on the left side of the top of the Change screen.
+
+image::images/cross-repository-changes-add-topic.png[width=600]
+
+=== 2. *Go through the normal code review process*
+
+Each change still goes through the normal code review process where reviewers
+vote on each change individually. The changes won’t be able to be submitted
+until *all* changes in the topic are submittable.
+
+The requirements for submittability vary based on rules set by your repository
+administrators; often this includes being approved by all requisite parties,
+passing presubmit testing, and being able to merge cleanly (without conflicts)
+into the target branch.
+
+=== 3. *Submit the change*
+
+When all changes in the topic are submittable, you’ll see *SUBMIT WHOLE TOPIC*
+at the top of the _Change screen_. Clicking it will submit all the changes in
+"Submitted Together."
+
+image::images/cross-repository-changes-submit-topic.png[width=600]
+
+[[reverting]]
+== Reverting a Submission
+
+After a topic is submitted, you can revert all or one of the changes by clicking
+the *REVERT* button on any change.
+
+image::images/cross-repository-changes-revert-topic.png[width=600]
+
+This will give you the option to either revert just the change in question or
+the entire topic:
+
+image::images/cross-repository-changes-revert-topic-options.png[width=600]
+
+Reverting the entire submission creates revert commits for each change and
+automatically associates them together under the same topic. To submit
+these changes, go through the normal review process.
+
+When submitting a topic, dependent changes and their topics are submitted as
+well. The RevertSubmission creates reverts for all the changes that were
+submitted at that time. When reverting the submission described in
+<<example_submission,Example Submission>>, all 4 of those changes will get
+reverted.
+
+|===
+| NOTE: We say “reverting a submission” instead of “reverting a submitted
+ topic” because submissions are defined by submission id, not by the topic
+ string. So even though topics names could be reused, this doesn't effect
+ reverting. For example:
+
+ 1. Submission #1 uses topic A
+
+ 2. Later, Submission #2 uses topic A again
+
+ Reverting submission #2 only reverts the changes in that submission, not all
+ changes included in topic A.
+|===
+
+== Cherry-Picking a Topic
+
+You may want to cherry-pick the changes (i.e. copy the changes) of a topic to
+another branch, perhaps because you have multiple branches that all need to be
+updated with the same change (e.g. you're porting a security fix across
+branches). Gerrit provides a mechanism to create these changes.
+
+From the overflow menu (3 dot icon) in the top right of the Change Screen,
+select “Cherry pick.” In the screenshot below, we’re showing this on a
+submitted change, but this option is available if the change is pending as
+well.
+
+image::images/cross-repository-changes-cp-menu.png[width=600]
+
+Afterwards, you’ll be presented with a modal where you can “Cherry Pick entire
+topic.”
+
+image::images/cross-repository-changes-cp-modal.png[width=600]
+
+Enter the branch name that you want to target for these repositories. The
+branch must already exist on all of the repositories. After clicking
+“CHERRY PICK,” Gerrit will create new changes all targeting the entered
+branch in their respective repositories, and these new changes will all be
+associated with a new, uniquely-generated topic name.
+
+To submit the cherry-picked changes, go through the normal submission
+process.
+
+|===
+| NOTE: You cannot cherry pick two or more changes that all target the same
+ repository from the Gerrit UI at this time; you’ll get an error message saying
+ “changes cannot be of the same repository.” To accomplish this, you’d
+ need to do the cherry-pick locally.
+|===
+
+== Searching for Topics
+
+In the Gerrit search bar, you can search for changes attached to a specific
+topic using the `topic` operator e.g. `topic:MY_TOPIC_NAME`. The `intopic`
+operator works similary but supports free-text and regular expression search.
+
+You can also search for a submission using the `submissionid` operator. Topic
+submission IDs are "<id>-<topic>" where id is the change number of the change
+that triggered the submission (though this could change in the future). As a
+full example, if the topic name is my-topic and change 12345 was the one that
+triggered submission, you could find it with `submissionid:12345-my-topic`.
+
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 8197550..747f761 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -255,7 +255,7 @@
with BUILD Files` button of link:https://ij.bazel.build[Bazel plugin,role=external,window=_blank].
[[documentation]]
-=== Documentation
+== Documentation
To build only the documentation for testing or static hosting:
@@ -318,6 +318,18 @@
bazel test //javatests/com/google/gerrit/acceptance/rest/account:rest_account
----
+To run SSH tests using JSch ssh client:
+
+----
+ bazel test --test_env=SSH_CLIENT_IMPLEMENTATION=JSCH //...
+----
+
+To run SSH tests using Apache MINA ssh client:
+
+----
+ bazel test --test_env=SSH_CLIENT_IMPLEMENTATION=APACHE //...
+----
+
To run only tests that do not use SSH:
----
@@ -375,6 +387,24 @@
for fine-grained test selection that can be combined with many of the examples
above.
+[[debugging-tests]]
+== Debugging Unit Tests
+In some cases it may be necessary to debug a test while running it in bazel. For example, when we
+observe a different test result in Eclipse and bazel. Using the `--java_debug` option will start the
+JVM in debug mode and await for a remote debugger to attach.
+
+Example:
+[source,bash]
+----
+ bazel test --java_debug --test_tag_filters=delete-project //...
+ ...
+ Listening for transport dt_socket at address: 5005
+ ...
+----
+
+Now attach with a debugger to the port `5005`. For example use "Remote Java Application" launch
+configuration in Eclipe and specify the port `5005`.
+
[[elasticsearch]]
=== Elasticsearch
diff --git a/Documentation/dev-crafting-changes.txt b/Documentation/dev-crafting-changes.txt
index 7935f30..15bf785 100644
--- a/Documentation/dev-crafting-changes.txt
+++ b/Documentation/dev-crafting-changes.txt
@@ -306,6 +306,30 @@
and it also makes `git revert` more useful.
* Use topics to link your separate changes together.
+[[opportunistic-refactoring]]
+== Opportunistic Refactoring
+
+Opportunistic Refactoring is a terminology
+link:https://martinfowler.com/bliki/OpportunisticRefactoring.html[used by Martin Fowler,role=external,window=_blank]
+also known as the "boy scout rule" of the software developer:
+"always leave the code behind in a better state than you found it."
+
+In practice, this rule means you should not add technical debt in the code while
+implementing a new feature or fixing a bug. If you or a reviewer find an
+opportunity to clean up the code during implementation or review of your change,
+take the time to do a little cleanup to improve the overall code base.
+
+When approaching refactoring, keep in mind that changes should do one thing
+(<<change-size,see change size section above>>). If a change you're making
+requires cleanup/refactoring, it is best to do that cleanup in a preparatory and
+separate change. Likewise, if during review for a functional change, an
+opportunity for cleanup/refactoring is discovered, then it is preferable to do
+the cleanup first in a separate change so as to improve the reviewability of the
+functional change.
+
+Reviewers should keep in mind the scope of the change under review and ensure
+suggested refactoring is aligned with that scope.
+
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/dev-design.txt b/Documentation/dev-design.txt
index c94862e..a41c9ea 100644
--- a/Documentation/dev-design.txt
+++ b/Documentation/dev-design.txt
@@ -18,83 +18,45 @@
== Background
-Google developed Mondrian, a Perforce based code review tool to
-facilitate peer-review of changes prior to submission to the central
-code repository. Mondrian is not open source, as it is tied to the
-use of Perforce and to many Google-only services, such as Bigtable.
-Google employees have often described how useful Mondrian and its
-peer-review process is to their day-to-day work.
-
-Guido van Rossum open sourced portions of Mondrian within Rietveld,
-a similar code review tool running on Google App Engine, but for
-use with Subversion rather than Perforce. Rietveld is in common
-use by many open source projects, facilitating their peer reviews
-much as Mondrian does for Google employees. Unlike Mondrian and
-the Google Perforce triggers, Rietveld is strictly advisory and
-does not enforce peer-review prior to submission.
-
Git is a distributed version control system, wherein each repository
is assumed to be owned/maintained by a single user. There are no
inherent security controls built into Git, so the ability to read
from or write to a repository is controlled entirely by the host's
-filesystem access controls. When multiple maintainers collaborate
-on a single shared repository a high degree of trust is required,
-as any collaborator with write access can alter the repository.
+filesystem or network access controls.
-Gitosis provides tools to secure centralized Git repositories,
-permitting multiple maintainers to manage the same project at once,
-by restricting the access to only over a secure network protocol,
-much like Perforce secures a repository by only permitting access
-over its network port.
+The objective of Gerrit is to facilitate Git development by larger
+teams: it provides a means to enforce organizational policies around
+code submissions, eg. "all code must be reviewed by another
+developer", "all code shall pass tests". It achieves this by
-The Android Open Source Project (AOSP) was founded by Google by the
-open source releasing of the Android operating system. AOSP has
-selected Git as its primary version control tool. As many of the
-engineers have a background of working with Mondrian at Google,
-there is a strong desire to have the same (or better) feature set
-available for Git and AOSP.
+* providing fine-grained (per-branch, per-repository, inheriting)
+ access controls, which allow a Gerrit admin to delegate permissions
+ to different team(-lead)s.
-Gerrit Code Review started as a simple set of patches to Rietveld,
-and was originally built to service AOSP. This quickly turned
-into a fork as we added access control features that Guido van
-Rossum did not want to see complicating the Rietveld code base. As
-the functionality and code were starting to become drastically
-different, a different name was needed. Gerrit calls back to the
-original namesake of Rietveld, Gerrit Rietveld, a Dutch architect.
-
-Gerrit 2.x is a complete rewrite of the Gerrit fork, completely
-changing the implementation from Python on Google App Engine, to Java
-on a J2EE servlet container and an SQL database.
-
-Since Gerrit 3.x link:note-db.html[NoteDb] replaced the SQL database
-and all metadata is now stored in Git.
-
-* link:http://video.google.com/videoplay?docid=-8502904076440714866[Mondrian Code Review On The Web,role=external,window=_blank]
-* link:https://github.com/rietveld-codereview/rietveld[Rietveld - Code Review for Subversion,role=external,window=_blank]
-* link:http://eagain.net/gitweb/?p=gitosis.git;a=blob;f=README.rst;hb=HEAD[Gitosis README,role=external,window=_blank]
-* link:http://source.android.com/[Android Open Source Project,role=external,window=_blank]
-
+* facilitate code review: Gerrit offers a web view of pending code
+ changes, that allows for easy reading and commenting by humans. The
+ web view can offer data coming out of automated QA processes (eg.
+ CI). The permission system also includes fine grained control of who
+ can approve pending changes for submission to further facilitate
+ delegation of code ownership.
== Overview
Developers create one or more changes on their local desktop system,
then upload them for review to Gerrit using the standard `git push`
-command line program, or any GUI which can invoke `git push` on
-behalf of the user. Authentication and data transfer are handled
-through SSH. Users are authenticated by username and public/private
-key pair, and all data transfer is protected by the SSH connection
-and Git's own data integrity checks.
+command line program, or any GUI which can invoke `git push` on behalf
+of the user. Authentication and data transfer are handled through SSH
+and HTTPS. Uploads are protected by the authentication,
+confidentiality and integrity offered by the transport (SSH, HTTPS).
-Each Git commit created on the client desktop system is converted
-into a unique change record which can be reviewed independently.
-Change records are stored in NoteDb.
+Each Git commit created on the client desktop system is converted into
+a unique change record which can be reviewed independently.
A summary of each newly uploaded change is automatically emailed
to reviewers, so they receive a direct hyperlink to review the
change on the web. Reviewer email addresses can be specified on the
-`git push` command line, but typically reviewers are automatically
-selected by Gerrit by identifying users who have change approval
-permissions in the project.
+`git push` command line, but typically reviewers are added in the web
+interface.
Reviewers use the web interface to read the side-by-side or unified
diff of a change, and insert draft inline/file comments where
@@ -103,20 +65,16 @@
emailed to the change author by Gerrit, and are CC'd to all other
reviewers who have already commented on the change.
-When publishing comments reviewers are also given the opportunity
-to score the change, indicating whether they feel the change is
-ready for inclusion in the project, needs more work, or should be
-rejected outright. These scores provide direct feedback to Gerrit's
-change submit function.
+Reviewers can score the change ("vote"), indicating whether they feel the
+change is ready for inclusion in the project, needs more work, or
+should be rejected outright. These scores provide direct feedback to
+Gerrit's change submit function.
-After a change has been scored positively by reviewers, Gerrit
-enables a submit button on the web interface. Authorized users
-can push the submit button to have the change enter the project
-repository. The equivalent in Subversion or Perforce would be
-that Gerrit is invoking `svn commit` or `p4 submit` on behalf of
-the web user pressing the button. Due to the way Git audit trails
-are maintained, the user pressing the submit button does not need
-to be the author of the change.
+After a change has been scored positively by reviewers, Gerrit enables
+a submit button on the web interface. Authorized users can push the
+submit button to have the change enter the project repository. The
+user pressing the submit button does not need to be the author of the
+change.
== Infrastructure
@@ -125,18 +83,30 @@
HTTP server. As nearly all of the user interface is implemented
through PolyGerrit, the majority of these requests are transmitting
compressed JSON payloads, with all HTML being generated within the
-browser. Most responses are under 1 KB.
+browser.
-Gerrit's HTTP server side component is implemented as a standard
-Java servlet, and thus runs within any J2EE servlet container.
-Popular choices for deployments would be Tomcat or Jetty, as these
-are high-quality open-source servlet containers that are readily
-available for download.
+Gerrit's HTTP server side component is implemented as a standard Java
+servlet, and thus runs within any link:install-j2ee.html[J2EE servlet
+container]. The standard install will run inside Jetty, which is
+included in the binary.
-End-user uploads are performed over SSH, so Gerrit's servlets also
-start up a background thread to receive SSH connections through
-an independent SSH port. SSH clients communicate directly with
-this port, bypassing the HTTP server used by browsers.
+End-user uploads are performed over SSH or HTTP, so Gerrit's servlets
+also start up a background thread to receive SSH connections through
+an independent SSH port. SSH clients communicate directly with this
+port, bypassing the HTTP server used by browsers.
+
+User authentication is handled by identity realms. Gerrit supports the
+following types of authentication:
+
+* OpenId (see link:http://openid.net/developers/specs/[OpenID Specifications,role=external,window=_blank])
+* OAuth2
+* LDAP
+* Google accounts (on googlesource.com)
+* SAML
+* Kerberos
+* 3rd party SSO
+
+=== NoteDb
Server side data storage for Gerrit is broken down into two different
categories:
@@ -156,28 +126,119 @@
local ones, due to Git disk IO behavior not being optimized for
remote access.
-The Gerrit metadata contains a summary of the available changes,
-all comments (published and drafts), and individual user account
-information. The metadata is mostly housed in the database (*1),
-which can be located either on the same server as Gerrit, or on
-a different (but nearby) server. Most installations would opt to
-install both Gerrit and the metadata database on the same server,
-to reduce administration overheads.
+The Gerrit metadata contains a summary of the available changes, all
+comments (published and drafts), and individual user account
+information.
-User authentication is handled by OpenID, and therefore Gerrit
-requires that the OpenID provider selected by a user must be
-online and operating in order to authenticate that user.
+Gerrit metadata is also stored in Git, with the commits marking the
+historical state of metadata. Data is stored in the trees associated
+with the commits, typically using Git config file or JSON as the base
+format. For metadata, there are 3 types of data: changes, accounts and
+groups.
-* link:http://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html[Git Repository Format,role=external,window=_blank]
-* link:http://openid.net/developers/specs/[OpenID Specifications,role=external,window=_blank]
+Accounts are stored in a special Git repository `All-Users`.
-*1 Although an effort is underway to eliminate the use of the
-database altogether, and to store all the metadata directly in
-the git repositories themselves. So far, as of Gerrit 2.2.1, of
-all Gerrit's metadata, only the project configuration metadata
-has been migrated out of the database and into the git
-repositories for each project.
+Accounts can be grouped in groups. Gerrit has a built-in group system,
+but can also interface to external group system (eg. Google groups,
+LDAP). The built-in groups are stored in `All-Users`.
+Draft comments are stored in `All-Users` too.
+
+Permissions are stored in Git, in a branch `refs/meta/config` for the
+repository. Repository configuration (including permissions) supports
+single inheritance, with the `All-Projects` repository containing
+site-wide defaults.
+
+Code review metadata is stored in Git, alongside the code under
+review. Metadata includes change status, votes, comments. This review
+metadata is stored in NoteDb along with the submitted code and code
+under review. Hence, the review history can be exported with `git
+clone --mirror` by anyone with sufficient permissions.
+
+== Permissions
+
+Permissions are specified on branch names, and given to groups. For
+example,
+
+```
+[access "refs/heads/stable/*"]
+ push = group Release-Engineers
+```
+
+this provides a rule, granting Release-Engineers push permission for
+stable branches.
+
+There are fundamentally two types of permissions:
+
+* Write permissions (who can vote, push, submit etc.)
+
+* Read permissions (who can see data)
+
+Read permissions need special treatment across Gerrit, because Gerrit
+should only surface data (including repository existence) if a user
+has read permission. This means that
+
+* The git wire protocol support must omit references from
+ advertisement if the user lacks read permissions
+
+* Uploads through the git wire protocol must refuse commits that are
+ based on SHA-1s for data that the user can't see.
+
+* Tags are only visible if their commits are visible to user through a
+ non-tag reference.
+
+Metadata (eg. OAuth credentials) is also stored in Git. Existing
+endpoints must refuse creating branches or changes that expose these
+metadata or allow changes to them.
+
+
+=== Indexing
+
+Almost all data is stored as Git, but Git only supports fast lookup by
+SHA-1 or by ref (branch) name. Therefore Gerrit also has an indexing
+system (powered by Lucene by default) for other types of queries.
+There are 4 indices:
+
+* Project index - find repositories by name, parent project, etc.
+* Account index - find accounts by name, email, etc.
+* Group index - find groups by name, owner, description etc.
+* Change index - find changes by file, status, modification date etc.
+
+The base entities are characterized by SHA-1s. Storing the
+characterizing SHA-1s allows detection of stale index entries.
+
+== Plug-in architecture
+
+Gerrit has a plug-in architecture. Plugins can be installed by
+dropping them into $site_directory/plugins, or at runtime through
+plugin SSH commands, or the plugin REST API.
+
+=== Backend plugins
+
+At runtime, code can be loaded from a `.jar` file. This code can hook
+into predefined extension points. A common use of plugins is to have
+Gerrit interoperate with site-specific tools, such as CI-systems or
+issue trackers.
+
+// list some notable extension points, and notable plugins
+// link to plugin development
+
+Some backend plugins expose the JVM for scripting use (eg. Groovy,
+Scala), so plugins can be written without having to setup a Java
+development environment.
+
+// Luca to expand: how do script plugins load their scripts?
+
+=== Frontend plugins
+
+The UI can be extended using Frontend plugins. This is useful for
+changing the look & feel of Gerrit, but it can also be used to surface
+data from systems that aren't integrated with the Gerrit backend, eg.
+CI systems or code coverage providers.
+
+// FE team to write a bit more:
+// * how to load ?
+// * XSRF, CORS ?
== Internationalization and Localization
@@ -189,14 +250,11 @@
and comments in English, and therefore an English user interface
is usable by the target user base.
-Right-to-left (RTL) support is only barely considered within the
-Gerrit code base. Some portions of the code have tried to take
-RTL into consideration, while others probably need to be modified
-before translating the UI to an RTL language.
-
== Accessibility Considerations
+// UI team to rewrite this.
+
Whenever possible Gerrit displays raw text rather than image icons,
so screen readers should still be able to provide useful information
to blind persons accessing Gerrit sites.
@@ -215,7 +273,9 @@
== Browser Compatibility
-Supporting non-JavaScript enabled browsers is a non-goal for Gerrit.
+Gerrit requires a JavaScript enabled browser.
+
+// UI team to add section on minimum browser requirements.
As Gerrit is a pure JavaScript application on the client side, with
no server side rendering fallbacks, the browser must support modern
@@ -223,54 +283,19 @@
Dumb clients such as `lynx`, `wget`, `curl`, or even many search engine
spiders are not able to access Gerrit content.
-There are number of web browsers available with full JavaScript
-support, and nearly every operating system (including any PDA-like
-mobile phone) comes with one standard. Users who are committed
-to developing changes for a Gerrit managed project can be expected
-to be able to run a JavaScript enabled browser, as they also would
-need to be running Git in order to contribute.
-
-There are a number of open source browsers available, including
-Firefox and Chromium. Users have some degree of choice in their
-browser selection, including being able to build and audit their
-browser from source.
-
-The majority of the content stored within Gerrit is also available
-through other means, such as gitweb or the `git://` protocol.
-Any existing search engine spider can crawl the server-side HTML
-produced by gitweb, and thus can index the majority of the changes
-which might appear in Gerrit. Some engines may even choose to
-crawl the native version control database, such as ohloh.net does.
-Therefore the lack of support for most search engine spiders is a
-non-issue for most Gerrit deployments.
+All of the content stored within Gerrit is also available through
+other means, such as gitweb or the `git://` protocol. Any existing
+search engine crawlers can index the server-side HTML served by a code
+browser, and thus can index the majority of the changes which might
+appear in Gerrit. Therefore the lack of support for most search engine
+crawlers is a non-issue for most Gerrit deployments.
== Product Integration
-Gerrit integrates with an existing gitweb installation by optionally
-creating hyperlinks to reference changes on the gitweb server.
-
-Gerrit integrates with an existing git-daemon installation by
-optionally displaying `git://` URLs for users to download a
-change through the native Git protocol.
-
-Gerrit integrates with any OpenID provider for user authentication,
-making it easier for users to join a Gerrit site and manage their
-authentication credentials to it. To make use of Google Accounts
-as an OpenID provider easier, Gerrit has a shorthand "Sign in with
-a Google Account" link on its sign-in screen. Gerrit also supports
-a shorthand sign in link for Yahoo!. Other providers may also be
-supported more directly in the future.
-
-Site administrators may limit the range of OpenID providers to
-a subset of "reliable providers". Users may continue to use
-any OpenID provider to publish comments, but granted privileges
-are only available to a user if the only entry point to their
-account is through the defined set of "reliable OpenID providers".
-This permits site administrators to require HTTPS for OpenID,
-and to use only large main-stream providers that are trustworthy,
-or to require users to only use a custom OpenID provider installed
-alongside Gerrit Code Review.
+Gerrit optionally surfaces links to HTML pages in a code browser. The
+links are configurable, and Gerrit comes with a built-in code browser,
+called Gitiles.
Gerrit integrates with some types of corporate single-sign-on (SSO)
solutions, typically by having the SSO authentication be performed
@@ -290,16 +315,17 @@
Gerrit does not integrate with any Google service, or any other
services other than those listed above.
+Plugins (see above) can be used to drive product integrations from the
+Gerrit side. Products that support Gerrit explicitly can use the REST
+API or the SSH API to contact Gerrit.
+
+
== Privacy Considerations
Gerrit stores the following information per user account:
* Full Name
* Preferred Email Address
-* Mailing Address '(Optional, Encrypted)'
-* Country '(Optional, Encrypted)'
-* Phone Number '(Optional, Encrypted)'
-* Fax Number '(Optional, Encrypted)'
The full name and preferred email address fields are shown to any
site visitor viewing a page containing a change uploaded by the
@@ -325,271 +351,145 @@
The user's name and email address is stored unencrypted in the
link:config-accounts.html#all-users[All-Users] repository.
-The snail-mail mailing address, country, and phone and fax numbers
-are gathered to help project leads contact the user should there
-be a legal question regarding any change they have uploaded.
-
-These sensitive fields are immediately encrypted upon receipt with
-a GnuPG public key, and stored "off site" in another data store,
-isolated from the main Gerrit change data. Gerrit does not have
-access to the matching private key, and as such cannot decrypt the
-information. Therefore these fields are write-once in Gerrit, as not
-even the account owner can recover the values they previously stored.
-
-It is expected that the address information would only need to be
-decrypted and revealed with a valid court subpoena, but this is
-really left to the discretion of the Gerrit site administrator as
-to when it is reasonable to reveal this information to a 3rd party.
-
-
== Spam and Abuse Considerations
-Gerrit makes no attempt to detect spam changes or comments. The
-somewhat high barrier to entry makes it unlikely that a spammer
-will target Gerrit.
+There is no spam protection for the Git protocol upload path.
+Uploading a change successfully requires a pre-existing account, and a
+lot of up-front effort.
-To upload a change, the client must speak the native Git protocol
-embedded in SSH, with some custom Gerrit semantics added on top.
-The client must have their public key already stored in the Gerrit
-database, which can only be done through the XSRF protected
-JSON-RPC interface. The level of effort required to construct
-the necessary tools to upload a well-formatted change that isn't
-rejected outright by the Git and Gerrit checksum validations is
-too high to for a spammer to get any meaningful return.
+Gerrit makes no attempt to detect spam changes or comments in the web
+UI. To post and publish a comment a client must sign in and then use
+the XSRF protected JSON-RPC interface to publish the draft on an
+existing change record.
-To post and publish a comment a client must sign in with an OpenID
-provider and then use the XSRF protected JSON-RPC interface to
-publish the draft on an existing change record. Again, the level of
-effort required to implement the Gerrit specific XSRF protections
-and the JSON-RPC payload format necessary to post a draft and then
-publish that draft is simply too high for a spammer to bother with.
-
-Both of these assumptions are also based upon the idea that Gerrit
-will be a lot less popular than blog software, and thus will be
-running on a lot fewer websites. Spammers therefore have very little
-returned benefit for getting over the protocol hurdles.
-
-These assumptions may need to be revisited in the future if any
-public Gerrit site actually notices spam.
-
-
-== Latency
-
-Gerrit targets for sub-250 ms per page request, mostly by using
-very compact JSON payloads between client and server. However, as
-most of the serving stack (network, hardware, metadata
-database) is out of control of the Gerrit developers, no real
-guarantees can be made about latency.
+Absence of SPAM handling is based upon the idea that Gerrit caters to
+a niche audience, and will therefore be unattractive to spammers. In
+addition, it is not a factor for corporate, on-premise deployments.
== Scalability
-Gerrit is designed for a very large scale open source project, or
-large commercial development project. Roughly this amounts to
-parameters such as the following:
+Gerrit supports the Git wire protocol, and an API (one API for HTTP,
+and one for SSH).
-.Design Parameters
-[options="header"]
-|======================================================
-|Parameter | Default Maximum | Estimated Maximum
-|Projects | 1,000 | 10,000
-|Contributors | 1,000 | 50,000
-|Changes/Day | 100 | 2,000
-|Revisions/Change | 20 | 20
-|Files/Change | 50 | 16,000
-|Comments/File | 100 | 100
-|Reviewers/Change | 8 | 8
-|======================================================
+The git wire protocol does a client/server negotiation to avoid
+sending too much data. This negotation occupies a CPU, so the number
+of concurrent push/fetch operations should be capped by the number of
+CPUs.
-Out of the box, Gerrit will handle the "Default Maximum". Site
-administrators may reconfigure their servers by editing gerrit.config
-to run closer to the estimated maximum if sufficient memory is made
-available to the JVM and the relevant cache.*.memoryLimit variables
-are increased from their defaults.
-
-=== Discussion
-
-Very few, if any open source projects have more than a handful of
-Git repositories associated with them. Since Gerrit treats each
-Git repository as a project, an upper limit of 10,000 projects
-is reasonable. If a site has more than 1,000 projects, administrators
-should increase
-link:config-gerrit.html#cache.name.memoryLimit[`cache.projects.memoryLimit`]
-to match.
-
-Almost no open source project has 1,000 contributors over all time,
-let alone on a daily basis. This default figure of 1,000 was WAG'd by
-looking at PR statements published by cell phone companies picking
-up the Android operating system. If all of the stated employees in
-those PR statements were working on *only* the open source Android
-repositories, we might reach the 1,000 estimate listed here. Knowing
-these companies as being very closed-source minded in the past, it
-is very unlikely all of their Android engineers will be working on
-the open source repository, and thus 1,000 is a very high estimate.
-
-The upper maximum of 50,000 contributors is based on existing
-installations that are already handling quite a bit more than the
-default maximum of 1,000 contributors. Given how the user data is
-stored and indexed, supporting 50,000 contributor accounts (or more)
-is easily possible for a server. If a server has more than 1,000
-*active* contributors,
-link:config-gerrit.html#cache.name.memoryLimit[`cache.accounts.memoryLimit`]
-should be increased by the site administrator, if sufficient RAM
-is available to the host JVM.
-
-The estimate of 100 changes per day was WAG'd off some estimates
-originally obtained from Android's development history. Writing a
-good change that will be accepted through a peer-review process
-takes time. The average engineer may need 4-6 hours per change just
-to write the code and unit tests. Proper design consideration and
-additional but equally important tasks such as meetings, interviews,
-training, and eating lunch will often pad the engineer's day out
-such that suitable changes are only posted once a day, or once
-every other day. For reference, the entire Linux kernel has an
-average of only 79 changes/day. If more than 100 changes are active
-per day, site administrators should consider increasing the
-link:config-gerrit.html#cache.name.memoryLimit[`cache.diff.memoryLimit`]
-and `cache.diff_intraline.memoryLimit`.
-
-On average any given change will need to be modified once to address
-peer review comments before the final revision can be accepted by the
-project. Executing these revisions also eats into the contributor's
-time, and is another factor limiting the number of changes/day
-accepted by the Gerrit instance. However, even though this implies
-only 2 revisions/change, many existing Gerrit installations have seen
-20 or more revisions/change, when new contributors are learning the
-project's style and conventions.
-
-On average, each change will have 2 reviewers, a human and an
-automated test bed system. Usually this would be the project lead, or
-someone who is familiar with the code being modified. The time
-required to comment further reduces the time available for writing
-one's own changes. However, existing Gerrit installations have seen 8
-or more reviewers frequently show up on changes that impact many
-functional areas, and therefore it is reasonable to expect 8 or more
-reviewers to be able to work together on a single change.
-
-Existing installations have successfully processed change reviews with
-more than 16,000 files per change. However, since 16,000 modified/new
-files is a massive amount of code to review, it is more typical to see
-less than 10 files modified in any single change. Changes larger than
-10 files are typically merges, for example integrating the latest
-version of an upstream library, where the reviewer has little to do
-beyond verifying the project compiles and passes a test suite.
-
-=== CPU Usage - Web UI
-
-Gerrit's web UI would require on average `4+F+F*C` HTTP requests to
-review a change and post comments. Here `F` is the number of files
-modified by the change, and `C` is the number of inline/file comments
-left by the reviewer per file. The constant 4 accounts for the request
-to load the reviewer's dashboard, to load the change detail page,
-to publish the review comments, and to reload the change detail
-page after comments are published.
-
-This WAG'd estimate boils down to 216,000 HTTP requests per day
-(QPD). Assuming these are evenly distributed over an 8 hour work day
-in a single time zone, we are looking at approximately 7.5 queries
-per second (QPS).
-
-----
- QPD = Changes_Day * Revisions_Change * Reviewers_Change * (4 + F + F * C)
- = 2,000 * 2 * 1 * (4 + 10 + 10 * 4)
- = 216,000
- QPS = QPD / 8_Hours / 60_Minutes / 60_Seconds
- = 7.5
-----
-
-Gerrit serves most requests in under 60 ms when using the loopback
-interface and a single processor. On a single CPU system there is
-sufficient capacity for 16 QPS. A dual processor system should be
-more than sufficient for a site with the estimated load described above.
-
-Given a more realistic estimate of 79 changes per day (from the
-Linux kernel) suggests only 8,532 queries per day, and a much lower
-0.29 QPS when spread out over an 8 hour work day.
-
-=== CPU Usage - Git over SSH/HTTP
-
-A 24 core server is able to handle ~25 concurrent `git fetch`
-operations per second. The issue here is each concurrent operation
-demands one full core, as the computation is almost entirely server
-side CPU bound. 25 concurrent operations is known to be sufficient to
-support hundreds of active developers and 50 automated build servers
-polling for updates and building every change. (This data was derived
-from an actual installation's performance.)
-
-Because of the distributed nature of Git, end-users don't need to
-contact the central Gerrit Code Review server very often. For `git
-fetch` traffic, link:pgm-daemon.html[replica mode] is known to be an
-effective way to offload traffic from the main server, permitting it
-to scale to a large user base without needing an excessive number of
-cores in a single system.
-
-Clients on very slow network connections (for example home office
-users on VPN over home DSL) may be network bound rather than server
-side CPU bound, in which case a core may be effectively shared with
-another user. Possible core sharing due to network bottlenecks
+Clients on slow network connections may be network bound rather than
+server side CPU bound, in which case a core may be effectively shared
+with another user. Possible core sharing due to network bottlenecks
generally holds true for network connections running below 10 MiB/sec.
-If the server's own network interface is 1 Gib/sec (Gigabit Ethernet),
-the system can really only serve about 10 concurrent clients at the
-10 MiB/sec speed, no matter how many cores it has.
+Deployments for large, distributed companies can replicate Git data to
+read-only replicas to offload fetch traffic. The read-only replicas
+should also serve this data using Gerrit to ensure that permissions
+are obeyed.
-=== Disk Usage
+The API serves requests of varying costs. Requests that originate in
+the UI can block productivity, so care has been taken to optimize
+these for latency, using the following techniques:
-The average size of a revision in the Linux kernel once compressed by
-Git is 2,327 bytes, or roughly 2 KiB. Over the course of a year a
-Gerrit server running with the estimated maximum parameters above might
-see an introduction of 1.4 GiB over the total set of 10,000 projects
-hosted in that server. This figure assumes the majority of the content
-is human written source code, and not large binary blobs such as disk
-images or media files.
+* Async calls: the UI becomes responsive before some UI elements
+ finished loading
-Production Gerrit installations have been tested, and are known to
-handle Git repositories in the multigigabyte range, storing binary
-files, ranging in size from a few kilobytes (for example compressed
-icons) to 800+ megabytes (firmware images, large uncompressed original
-artwork files). Best practices encourage breaking very large binary
-files into their Git repositories based on access, to prevent desktop
-clients from needing to clone unnecessary materials (for example a C
-developer does not need every 800+ megabyte firmware image created by
-the product's quality assurance team).
+* Caching: metadata is stored in Git, which is relatively expensive to
+ access. This is sped up by multiple caches. Metadata entities are
+ stored in Git, and can therefore be seen as immutable values keyed
+ by SHA-1, which is very amenable to caching. All SHA-1 keyed caches
+ can be persisted on local disk.
+
+ The size (memory, disk) of these caches should be adapted to the
+ instance size (number of users, size and quantity of repositories)
+ for optimal performance.
+
+Git does not impose fundamental limits (eg. number of files per
+change) on data. To ensure stability, Gerrit configures a number of
+default limits for these.
+
+// add a link to the default settings.
+
+=== Scaling team size
+
+A team of size N has N^2 possible interactions. As a result, features
+that expose interactions with activities of other team members has a
+quadratic cost in aggregate. The following features scale poorly with
+large team sizes:
+
+* the change screen shows conflicting changes by default. This data is
+ cached, but updates to pending changes cause cache misses. For a
+ single change, the amount of work is proportional to the number of
+ pending changes, so in aggregate, the cost of this feature is
+ quadratic in the team size.
+
+* the change screen shows if a change is mergeable to the target
+ branch. If the target branch moves quickly (large developer team),
+ this causes cache misses. In aggregate, the cost of this feature is
+ also quadratic.
+
+Both features should be turned off for repositories that involve 1000s
+of developers.
+
+=== Browser performance
+
+// say something about browser performance tuning.
+
+=== Real life numbers
+
+
+Gerrit is designed for very large projects, both open source and
+proprietary commercial projects. For a single Gerrit process, the
+following limits are known to work:
+
+.Observed maximums
+[options="header"]
+|======================================================
+|Parameter | Maximum | Deployment
+|Projects | 50,000 | gerrithub.io
+|Contributors | 150,000 | eclipse.org
+|Bytes/repo | 100G | Qualcomm internal
+|Changes/repo | 300k | Qualcomm internal
+|Revisions/Change | 300 | Qualcomm internal
+|Reviewers/Change | 87 | Qualcomm internal
+|======================================================
+
+
+// find some numbers for these stats:
+// |Files/repo | ? |
+// |Files/Change | ? |
+// |Comments/Change | ? |
+// |max QPS/CPU | ? |
+
+
+Google runs a horizontally scaled deployment. We have seen the
+following per-JVM maximums:
+
+.Observed maximums (googlesource.com)
+[options="header"]
+|======================================================
+|Parameter | Maximum | Deployment
+|Files/repo | 500,000 | chromium-review
+|Bytes/repo | 12G | chromium-review
+|Changes/repo | 500k | chromium-review
+|Revisions/Change | 1900 | chromium-review
+|Files/Change | 10,000| android-review
+|Comments/Change | 1,200 | chromium-review
+|======================================================
+
== Redundancy & Reliability
-Gerrit largely assumes that the local filesystem where Git repository
-data is stored is always available. Important data written to disk
-is also forced to the platter with an `fsync()` once it has been
-fully written. If the local filesystem fails to respond to reads
-or becomes corrupt, Gerrit has no provisions to fallback or retry
-and errors will be returned to clients.
+Gerrit is structured as a single JVM process, reading and writing to a
+single file system. If there are hardware failures in the machine
+running the JVM, or the storage holding the repositories, there is no
+recourse; on failure, errors will be returned to the client.
-Gerrit largely assumes that the metadata database is online and
-answering both read and write queries. Query failures immediately
-result in the operation aborting and errors being returned to the
-client, with no retry or fallback provisions.
+Deployments needing more stringent uptime guarantees can use
+replication/multi-master setup, which ensures availability and
+geographical distribution, at the cost of slower write actions.
-Due to the relatively small scale described above, it is very likely
-that the Git filesystem and metadata database are all housed on the
-same server that is running Gerrit. If any failure arises in one of
-these components, it is likely to manifest in the others too. It is
-also likely that the administrator cannot be bothered to deploy a
-cluster of load-balanced server hardware, as the scale and expected
-load does not justify the hardware or management costs.
-
-Most deployments caring about reliability will setup a warm-spare
-standby system and use a manual fail-over process to switch from the
-failed system to the warm-spare.
-
-As Git is a distributed version control system, and open source
-projects tend to have contributors from all over the world, most
-contributors will be able to tolerate a Gerrit down time of several
-hours while the administrator is notified, signs on, and brings the
-warm-spare up. Pending changes are likely to need at least 24 hours
-of time on the Gerrit site anyway in order to ensure any interested
-parties around the world have had a chance to comment. This expected
-lag largely allows for some downtime in a disaster scenario.
+// TODO: link.
=== Backups
@@ -603,7 +503,8 @@
== Logging Plan
-Gerrit does not maintain logs on its own.
+Gerrit stores Apache style HTTPD logs, as well as ERROR/INFO messages
+from the Java logger, under `$site_dir/logs/`.
Published comments contain a publication date, so users can judge
when the comment was posted and decide if it was "recent" or not.
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 159e2fc..fb17e5c 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -2230,7 +2230,7 @@
light-weight plugin that links commits to external
tools (GitBlit, CGit, company specific resources etc).
-PatchSetWebLinks will appear to the right of the commit-SHA1 in the UI.
+PatchSetWebLinks will appear to the right of the commit-SHA-1 in the UI.
[source, java]
----
@@ -2256,7 +2256,7 @@
}
----
-ParentWebLinks will appear to the right of the SHA1 of the parent
+ParentWebLinks will appear to the right of the SHA-1 of the parent
revisions in the UI. The implementation should in most use cases direct
to the same external service as PatchSetWebLink; it is provided as a
separate interface because not all users want to have links for the
@@ -2546,14 +2546,13 @@
Compiled plugins and extensions can be deployed to a running Gerrit
server using the link:cmd-plugin-install.html[plugin install] command.
-Web UI plugins distributed as a single `.js` file (or `.html` file for
-Polygerrit) can be deployed without the overhead of JAR packaging. For
-more information refer to link:cmd-plugin-install.html[plugin install]
-command.
+Web UI plugins distributed as a single `.js` file can be deployed without the
+overhead of JAR packaging. For more information refer to
+link:cmd-plugin-install.html[plugin install] command.
Plugins can also be copied directly into the server's directory at
-`$site_path/plugins/$name.(jar|js|html)`. For Web UI plugins, the name
-of the file, minus the `.js` or `.html` extension, will be used as the
+`$site_path/plugins/$name.(jar|js)`. For Web UI plugins, the name
+of the file, minus the `.js` extension, will be used as the
plugin name. For JAR plugins, the value of the `Gerrit-PluginName`
manifest attribute will be used, if provided, otherwise the name of
the file, minus the `.jar` extension, will be used.
diff --git a/Documentation/dev-release.txt b/Documentation/dev-release.txt
index a7240e2..0849c56 100644
--- a/Documentation/dev-release.txt
+++ b/Documentation/dev-release.txt
@@ -153,7 +153,7 @@
Tag the plugins:
----
- git submodule foreach '[ "$path" == "modules/jgit" ] || git tag -s -m "v$version" "v$version"'
+ git submodule foreach '[ "$sm_path" == "modules/jgit" ] || git tag -s -m "v$version" "v$version"'
----
[[build-gerrit]]
@@ -324,7 +324,7 @@
Push the new Release Tag on the plugins:
----
- git submodule foreach git push gerrit-review tag v$version
+ git submodule foreach '[ "$sm_path" == "modules/jgit" ] || git push gerrit-review tag "v$version"'
----
[[upload-documentation]]
diff --git a/Documentation/error-commit-already-exists.txt b/Documentation/error-commit-already-exists.txt
index d2b7c9d..2832c78 100644
--- a/Documentation/error-commit-already-exists.txt
+++ b/Documentation/error-commit-already-exists.txt
@@ -1,6 +1,6 @@
= commit already exists
-With "commit already exists (as current patchset)" or
+With "commit(s) already exists (as current patchset)" or
"commit already exists (in the change)" error message
Gerrit rejects to push a commit to an existing change via
`refs/changes/n` if the commit was already successfully
diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt
new file mode 100644
index 0000000..2b40b5b
--- /dev/null
+++ b/Documentation/glossary.txt
@@ -0,0 +1,50 @@
+:linkattrs:
+= Glossary
+
+[[event]]
+== Event
+
+It refers to the link:https://gerrit.googlesource.com/gerrit/+/refs/heads/master/java/com/google/gerrit/server/events/Event.java[com.google.gerrit.server.events.Event]
+base abstract class representing any possible action that is generated or
+received in a Gerrit instance. Actions can be associated with change set status
+updates, project creations, indexing of changes, etc.
+
+[[event-broker]]
+== Event broker
+
+Distributes Gerrit Events to listeners if they are allowed to see them.
+
+[[event-dispatcher]]
+== Event dispatcher
+
+Interface for posting events to the Gerrit event system. Implemented by default
+by link:https://gerrit.googlesource.com/gerrit/+/refs/heads/master/java/com/google/gerrit/server/events/EventBroker.java[com.google.gerrit.server.events.EventBroker].
+It can be implemented by plugins and allows to influence how events are managed.
+
+[[event-hierarchy]]
+== Event hierarchy
+
+Hierarchy of events representing anything that can happen in Gerrit.
+
+[[event-listener]]
+== Event listener
+
+API for listening to Gerrit events from plugins, without having any
+visibility restrictions.
+
+[[stream-events]]
+== Stream events
+
+Command that allows a user via CLI or a plugin to receive in a sequential way
+some events that are generated in Gerrit. The consumption of the stream by default
+is available via SSH connection.
+However, plugins can provide an alternative implementation of the event
+brokering by sending them over a reliable messaging queueing system (RabbitMQ)
+or a pub-sub (Kafka).
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/images/cross-repository-changes-add-topic.png b/Documentation/images/cross-repository-changes-add-topic.png
new file mode 100644
index 0000000..fc85b8f
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-add-topic.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-cp-menu.png b/Documentation/images/cross-repository-changes-cp-menu.png
new file mode 100644
index 0000000..e9004f8
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-cp-menu.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-cp-modal.png b/Documentation/images/cross-repository-changes-cp-modal.png
new file mode 100644
index 0000000..a4790fb
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-cp-modal.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-example.png b/Documentation/images/cross-repository-changes-example.png
new file mode 100644
index 0000000..e790f71
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-example.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-revert-topic-options.png b/Documentation/images/cross-repository-changes-revert-topic-options.png
new file mode 100644
index 0000000..f2e9f1a
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-revert-topic-options.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-revert-topic.png b/Documentation/images/cross-repository-changes-revert-topic.png
new file mode 100644
index 0000000..8d87191
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-revert-topic.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-submit-topic.png b/Documentation/images/cross-repository-changes-submit-topic.png
new file mode 100644
index 0000000..7e96743
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-submit-topic.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-submitted-together.png b/Documentation/images/cross-repository-changes-submitted-together.png
new file mode 100644
index 0000000..e7ea334
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-submitted-together.png
Binary files differ
diff --git a/Documentation/images/cross-repository-changes-topic.png b/Documentation/images/cross-repository-changes-topic.png
new file mode 100644
index 0000000..12d0e38
--- /dev/null
+++ b/Documentation/images/cross-repository-changes-topic.png
Binary files differ
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 8f36ecc..e56e7ca 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -38,6 +38,7 @@
... link:user-changeid.html[Change-Id Lines]
... link:user-signedoffby.html[Signed-off-by Lines]
... link:user-change-cleanup.html[Change Cleanup]
+... link:cross-repository-changes.html[Cross Repository Changes using Topics]
== Project Management
. link:project-configuration.html[Project Configuration]
@@ -78,6 +79,7 @@
. link:note-db.html[NoteDb]
. link:config-accounts.html[Accounts on NoteDb]
. link:config-groups.html[Groups on NoteDb]
+. link:user-privacy.html[User data and privacy]
== Concepts
. link:config-labels.html[Review Labels]
@@ -85,6 +87,7 @@
. link:concept-changes.html[Changes]
. link:concept-refs-for-namespace.html[The refs/for Namespace]
. link:concept-patch-sets.html[Patch Sets]
+. link:glossary.html[Glossary]
== Resources
* link:licenses.html[Licenses and Notices]
diff --git a/Documentation/intro-gerrit-walkthrough-github.txt b/Documentation/intro-gerrit-walkthrough-github.txt
index f16155b..8f3ff88 100644
--- a/Documentation/intro-gerrit-walkthrough-github.txt
+++ b/Documentation/intro-gerrit-walkthrough-github.txt
@@ -206,8 +206,8 @@
When you `git commit --amend` to iterate on your change, you might be worried that
you are changing your previous commit and may thus lose that state of your work.
However, here the Change-Id appended to your commit message comes into play.
-While the SHA1 hash of your change (the commit ID used by Git) might change, the
-Change-Id stays the same (in fact it is the SHA1 hash of the very first version
+While the SHA-1 hash of your change (the commit ID used by Git) might change, the
+Change-Id stays the same (in fact it is the SHA-1 hash of the very first version
of that commit). When this amended commit is uploaded to the Gerrit server,
Gerrit knows that this commit is really an iteration of that previous commit
(and the associated review) and will preserve both, the old and the new state.
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt
index eb2025c..0408d5d 100644
--- a/Documentation/intro-user.txt
+++ b/Documentation/intro-user.txt
@@ -514,6 +514,9 @@
$ git push origin HEAD:refs/heads/master -o topic=multi-master
----
+For more information about using topics, see the user guide:
+link:cross-repository-changes.html[Submitting Changes Across Repositories by using Topics].
+
[[hashtags]]
== Using Hashtags
diff --git a/Documentation/js_licenses.txt b/Documentation/js_licenses.txt
index 7ef9473..b2dcfb8 100644
--- a/Documentation/js_licenses.txt
+++ b/Documentation/js_licenses.txt
@@ -362,15 +362,19 @@
* @polymer/neon-animation
* @polymer/paper-behaviors
* @polymer/paper-button
+* @polymer/paper-card
* @polymer/paper-dialog
* @polymer/paper-dialog-behavior
* @polymer/paper-dialog-scrollable
+* @polymer/paper-dropdown-menu
* @polymer/paper-icon-button
* @polymer/paper-input
* @polymer/paper-item
* @polymer/paper-listbox
+* @polymer/paper-menu-button
* @polymer/paper-tabs
* @polymer/paper-toggle-button
+* @polymer/paper-tooltip
[[Polymer-2015_license]]
----
@@ -412,6 +416,52 @@
----
+[[Polymer-2016]]
+Polymer-2016
+
+* @polymer/iron-image
+* @polymer/paper-checkbox
+
+[[Polymer-2016_license]]
+----
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
[[Polymer-2017]]
Polymer-2017
diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt
index 5f0fb65..63601d2 100644
--- a/Documentation/licenses.txt
+++ b/Documentation/licenses.txt
@@ -84,6 +84,7 @@
* mime4j:dom
* mina:core
* mina:sshd
+* mina:sshd-sftp
* openid:consumer
* openid:nekohtml
* openid:xerces
@@ -2348,6 +2349,7 @@
* jgit
* jgit-archive
* jgit-servlet
+* jgit-ssh-apache
[[jgit_license]]
----
@@ -3319,15 +3321,19 @@
* @polymer/neon-animation
* @polymer/paper-behaviors
* @polymer/paper-button
+* @polymer/paper-card
* @polymer/paper-dialog
* @polymer/paper-dialog-behavior
* @polymer/paper-dialog-scrollable
+* @polymer/paper-dropdown-menu
* @polymer/paper-icon-button
* @polymer/paper-input
* @polymer/paper-item
* @polymer/paper-listbox
+* @polymer/paper-menu-button
* @polymer/paper-tabs
* @polymer/paper-toggle-button
+* @polymer/paper-tooltip
[[Polymer-2015_license]]
----
@@ -3369,6 +3375,52 @@
----
+[[Polymer-2016]]
+Polymer-2016
+
+* @polymer/iron-image
+* @polymer/paper-checkbox
+
+[[Polymer-2016_license]]
+----
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
[[Polymer-2017]]
Polymer-2017
diff --git a/Documentation/logs.txt b/Documentation/logs.txt
index 6624366..ba370b1 100644
--- a/Documentation/logs.txt
+++ b/Documentation/logs.txt
@@ -51,6 +51,11 @@
* `referer`: the `Referer` HTTP request header. This gives the site that
the client reports having been referred from.
* `client agent`: the client agent which sent the request.
+* `total_cpu`: total CPU time, CPU time in milliseconds to execute command.
+* `user_cpu`: user mode CPU time, CPU time in user mode in milliseconds to execute command.
+ CPU time in kernel mode is `total_cpu - user_cpu`.
+* `memory`: memory allocated in bytes to execute command. -1 if the JVM does
+ not support this metric.
Example:
```
@@ -84,6 +89,11 @@
* `wait`: command wait time, time in milliseconds the command waited for an execution thread.
* `exec`: command execution time, time in milliseconds to execute the command.
* `status`: status code. 0 means success, any other value is an error.
+* `total_cpu`: total CPU time, CPU time in milliseconds to execute command.
+* `user_cpu`: user mode CPU time, CPU time in user mode in milliseconds to execute command.
+ CPU time in kernel mode is `total_cpu - user_cpu`.
+* `memory`: memory allocated in bytes to execute command. -1 if the JVM does
+ not support this metric.
The `git-upload-pack` command provides the following additional fields after the `exec`
and before the `status` field. All times are in milliseconds. Fields are -1 if not available
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index d3bea00..7a35d4d 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -50,6 +50,9 @@
objects needing finalization.
* `proc/jvm/gc/count`: Number of GCs.
* `proc/jvm/gc/time`: Approximate accumulated GC elapsed time.
+* `proc/jvm/memory/pool/committed/<pool name>`: Committed amount of memory for pool.
+* `proc/jvm/memory/pool/max/<pool name>`: Maximum amount of memory for pool.
+* `proc/jvm/memory/pool/used/<pool name>`: Used amount of memory for pool.
* `proc/jvm/thread/num_live`: Current live thread count.
* `proc/jvm/thread/num_daemon_live`: Current live daemon threads count.
* `proc/jvm/thread/num_peak_live`: Peak live thread count since the Java virtual machine started or peak was reset.
@@ -186,6 +189,8 @@
* `git/upload-pack/phase_compressing`: Time spent in the 'Compressing...' phase.
* `git/upload-pack/phase_writing`: Time spent transferring bytes to client.
* `git/upload-pack/pack_bytes`: Distribution of sizes of packs sent to clients.
+* `git/auto-merge/num_operations`: Number of auto merge operations and context.
+* `git/auto-merge/latency`: Latency of auto merge operations and context.
=== BatchUpdate
diff --git a/Documentation/note-db.txt b/Documentation/note-db.txt
index a13cbfb..b376d6e 100644
--- a/Documentation/note-db.txt
+++ b/Documentation/note-db.txt
@@ -36,6 +36,67 @@
not available in 3.0, so any upgrade from Gerrit 2.x to 3.x must go through
2.16 to effect the NoteDb upgrade.
+== Format
+
+Each review ("change") in Gerrit is numbered. The different revisions
+("patchsets") of a change 12345 are stored under
+----
+ refs/changes/45/12345/${PATCHSET_NUMBER}
+----
+
+The revisions are stored as commits to the main project, ie. if you
+fetch this ref, you can check out the proposed change.
+
+A change 12345 has its review metadata under
+----
+ refs/changes/45/12345/meta
+----
+The metadata is a notes branch. The commit messages on the branch hold
+modifications to global data of the change (votes, global comments). The inline
+comments are in a
+link:https://git.eclipse.org/r/plugins/gitiles/jgit/jgit/\+/master/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java[NoteMap],
+where the key is the commit SHA-1 of the patchset
+that the comment refers to, and the value is JSON data. The format of the
+JSON is in the
+link:https://gerrit.googlesource.com/gerrit/\+/master/java/com/google/gerrit/server/notedb/RevisionNoteData.java[RevisionNoteData]
+which contains
+link:https://gerrit.googlesource.com/gerrit/\+/master/java/com/google/gerrit/entities/Comment.java[Comment] entities.
+
+For example:
+----
+ {
+ "key": {
+ "uuid": "c7be1334_47885e36",
+ "filename":
+"java/com/google/gerrit/server/restapi/project/CommitsCollection.java",
+ "patchSetId": 7
+ },
+ "lineNbr": 158,
+ "author": {
+ "id": 1026112
+ },
+ "writtenOn": "2019-11-06T09:00:50Z",
+ "side": 1,
+ "message": "nit: factor this out in a variable, use
+toImmutableList as collector",
+ "range": {
+ "startLine": 156,
+ "startChar": 32,
+ "endLine": 158,
+ "endChar": 66
+ },
+ "revId": "071c601d6ee1a2a9f520415fd9efef8e00f9cf60",
+ "serverId": "173816e5-2b9a-37c3-8a2e-48639d4f1153",
+ "unresolved": true
+ },
+----
+
+Automated systems may post "robot comments" instead of normal
+comments, which are an extension of the previous comment, defined in
+the
+link:https://gerrit.googlesource.com/gerrit/\+/master/java/com/google/gerrit/entities/RobotComment.java[RobotComment]
+class.
+
[[migration]]
== Migration
diff --git a/Documentation/project-configuration.txt b/Documentation/project-configuration.txt
index 23030a4..e583f45 100644
--- a/Documentation/project-configuration.txt
+++ b/Documentation/project-configuration.txt
@@ -108,6 +108,9 @@
=== Default Branch
The default branch of a remote repository is defined by its `HEAD`.
+The default branch is selected from the initial branches of the newly created project,
+or set to link:config-gerrit.html#gerrit.defaultBranch[host-level default],
+if the project was created with empty branches.
For convenience reasons, when the repository is cloned Git creates a
local branch for this default branch and checks it out.
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index f66d430..a6a9cb7 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -565,10 +565,70 @@
----
Historical state of the change can be retrieved by specifying the
-`meta=SHA1` parameter. This will use a historical NoteDb snapshot to
-populate ChangeInfo. If the SHA1 is not reachable as a NoteDb state,
+`meta=SHA-1` parameter. This will use a historical NoteDb snapshot to
+populate ChangeInfo. If the SHA-1 is not reachable as a NoteDb state,
status code 412 is returned.
+[[get-meta-diff]]
+=== Get Meta Diff
+--
+'GET /changes/link:#change-id[\{change-id\}]/meta_diff?old=SHA-1&meta=SHA-1'
+--
+
+Retrieves the difference between two historical states of a change
+by specifying the `old=SHA-1` and the `meta=SHA-1` parameters.
+
+If the `old` parameter is not provided, the parent of the `meta`
+SHA-1 is used. If the `meta` parameter is not provided, the current
+state of the change is used. If neither are provided, the
+difference between the current state of the change and its previous
+state is returned.
+
+Additional fields can be obtained by adding `o` parameters, analogous
+to link:#get-change[Get Change], and the same concerns for Get Change hold for
+this endpoint too. Fields are described in link:#list-changes[Query Changes].
+
+.Request
+----
+ GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/meta_diff?old=b083abc34eb6dbdb9e154ba092fc198000e997b4&meta=63b81f2bde703ae07787a940e8fdf9a1828605b1 HTTP/1.0
+----
+
+As a response, two link:#change-info[ChangeInfo] entities are returned
+that describe information added and removed from the `old` change state.
+Only fields that differ between the change's two states are returned.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ {
+ "added": {
+ "attention_set": [
+ {
+ "account": {
+ "name": "John Doe"
+ },
+ "last_update": "2013-02-21 11:16:36.775000000",
+ "reason": "reviewer or cc replied"
+ }
+ ]
+ "updated": "2013-02-21 11:16:36.775000000",
+ "topic": "new-topic"
+ },
+ "removed": {
+ "updated": "2013-02-20 12:05:34.111000000",
+ "topic": "old-topic"
+ }
+ }
+----
+
+If the provided SHA-1 for `meta` is not reachable as a NoteDb
+state, the status code 412 is returned. If the SHA-1 for `old`
+is not reachable, the difference between the change at state
+`meta` and an empty change is returned.
[[get-change-detail]]
=== Get Change Detail
@@ -1140,7 +1200,7 @@
--
Check if the given change is a pure revert of the change it references in `revertOf`.
-Optionally, the query parameter `o` can be passed in to specify a commit (SHA1 in
+Optionally, the query parameter `o` can be passed in to specify a commit (SHA-1 in
40 digit hex representation) to check against. It takes precedence over `revertOf`.
If the change has no reference in `revertOf`, the parameter is mandatory.
@@ -2180,6 +2240,10 @@
comments for each path are sorted by patch set number. Each comment has
the `patch_set` field set, and no `author`.
+The `enable-context` and `context-padding` request parameters can be used to
+request comment context. See link:#list-change-comments[List Change Comments]
+for more details.
+
.Request
----
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/drafts HTTP/1.0
@@ -3509,6 +3573,9 @@
Deletes a single vote from a change. Note, that even when the last vote of
a reviewer is removed the reviewer itself is still listed on the change.
+If another user removed a user's vote, the user with the deleted vote will be
+added to the attention set.
+
.Request
----
DELETE /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/reviewers/John%20Doe/votes/Code-Review HTTP/1.0
@@ -5873,6 +5940,9 @@
Note, that even when the last vote of a reviewer is removed the reviewer itself
is still listed on the change.
+If another user removed a user's vote, the user with the deleted vote will be
+added to the attention set.
+
.Request
----
DELETE /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/reviewers/John%20Doe/votes/Code-Review HTTP/1.0
@@ -6051,6 +6121,9 @@
* The change is marked ready for review.
* As an owner/uploader, when someone replies on your change.
* As a reviewer, when the owner/uploader replies.
+* When the user's vote is deleted by another user.
+* The rules above (except manually adding to the attention set) don't apply
+ for changes that are work in progress.
Users are removed from the attention set if one the following apply:
@@ -6474,7 +6547,7 @@
(in which case it will only contain a key for the current revision) or
if link:#all-revisions[all revisions] are requested.
|`meta_rev_id` |optional|
-The SHA1 of the NoteDb meta ref.
+The SHA-1 of the NoteDb meta ref.
|`tracking_ids` |optional|
A list of link:#tracking-id-info[TrackingIdInfo] entities describing
references to external tracking systems. Only set if
@@ -6712,7 +6785,7 @@
Contains the link:rest-api-changes.html#change-message-info[id] of the change
message that this comment is linked to.
|`commit_id` |optional|
-Hex commit SHA1 (40 characters string) of the commit of the patchset to which
+Hex commit SHA-1 (40 characters string) of the commit of the patchset to which
this comment applies.
|`context_lines` |optional|
A list of link:#context-line[ContextLine] containing the lines of the source
@@ -7504,7 +7577,7 @@
|===========================
|Field Name ||Description
|`base` |optional|
-The new parent revision. This can be a ref or a SHA1 to a concrete patchset. +
+The new parent revision. This can be a ref or a SHA-1 to a concrete patchset. +
Alternatively, a change number can be specified, in which case the current
patch set is inferred. +
Empty string is used for rebasing directly on top of the target branch,
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index a8d9b3d..6ca2b46 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -1941,6 +1941,9 @@
|Field Name ||Description
|`has_avatars` |not set if `false`|
Whether an avatar provider is registered.
+|`js_resource_paths`||
+A list of relative paths (strings). Each path points to a frontend plugin that
+should be loaded, e.g. `plugins/codemirror_editor/static/codemirror_editor.js`.
|===========================
[[receive-info]]
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 49bc7e5..e30ce3a 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -4211,8 +4211,10 @@
|`branches` |optional|
A list of branches that should be initially created. +
For the branch names the `refs/heads/` prefix can be omitted. +
-The first entry of the list will be the default branch (ie. the target
-of the `HEAD` symbolic ref). +
+The first entry of the list will be the
+link:project-configuration.html#default-branch[default branch]. +
+If the list is empty, link:config-gerrit.html#gerrit.defaultBranch[host-level default]
+is used. +
Branches in the Gerrit internal ref space are not allowed, such as
refs/groups/, refs/changes/, etc...
|`owners` |optional|
diff --git a/Documentation/user-attention-set.txt b/Documentation/user-attention-set.txt
index 5e2906f..5053d10 100644
--- a/Documentation/user-attention-set.txt
+++ b/Documentation/user-attention-set.txt
@@ -47,7 +47,11 @@
attention set.
* For merged and abandoned changes the owner is added only when a human creates
an unresolved comment.
+* If another user removed a user's vote, the user with the deleted vote will be
+ added to the attention set.
* Only owner, uploader, reviewers and ccs can be in the attention set.
+* The rules for service accounts are different, see link:#bots[Bots].
+* Users are not added by automatic rules when the change is work in progress.
*!IMPORTANT!* These rules are not meant to be super smart and to always do the
right thing, e.g. if the change owner sends a reply, then they are often
@@ -85,7 +89,7 @@
image::images/user-attention-set-reply-select.png["reply dialog section for selecting users", align="center"]
-=== Bots
+=== Bots [[bots]]
The attention set is meant for human reviews only. Triggering bots and reacting
to their results is a different workflow and not in scope of the attenion set.
diff --git a/Documentation/user-inline-edit.txt b/Documentation/user-inline-edit.txt
index cd26792..4a9d18f 100644
--- a/Documentation/user-inline-edit.txt
+++ b/Documentation/user-inline-edit.txt
@@ -38,11 +38,11 @@
* Select branch for new change: Specify the destination branch of the
change.
- * Provide base commit SHA1 for change: Leave this field blank.
+ * Provide base commit SHA-1 for change: Leave this field blank.
+
-IMPORTANT: Git uses a unique SHA1 value to identify each and every commit (in
-other words, each Git commit generates a new SHA1 hash). This value differs
+IMPORTANT: Git uses a unique SHA-1 value to identify each and every commit (in
+other words, each Git commit generates a new SHA-1 hash). This value differs
from a Gerrit Change-Id, which is used by Gerrit to uniquely identify a
change. The Gerrit Change-Id remains static throughout the life of a Gerrit
change.
diff --git a/Documentation/user-privacy.txt b/Documentation/user-privacy.txt
new file mode 100644
index 0000000..d61ee76
--- /dev/null
+++ b/Documentation/user-privacy.txt
@@ -0,0 +1,113 @@
+:linkattrs:
+= Gerrit Code Review - User Privacy
+
+== Purpose
+
+This page documents how Gerrit handles user data.
+
+|===
+| Note: Gerrit has extensive support for link:config-plugins.html[plugins]
+ which extend Gerrits functionality, and these plugins could access, export, or
+ maniuplate user data. This document only focuses on the behavior of Gerrit
+ core and its link:dev-core-plugins.html[core plugins].
+|===
+
+== Types of User Data
+
+Gerrit stores account data required for collaborating on source code changes.
+This data is described by
+link:config-accounts.html#account-data-in-user-branch[Account Data in User
+Branch] and includes link:config-accounts.html#external-ids[External IDs],
+link:config-accounts.html#preferences[User Preferences],
+link:config-accounts.html#project-watches[Project Watches] and personally
+identifiable information, including name and email address. The email
+address is required to associate Git commits with a Gerrit user account. All
+data except passwords is made accessible to other users who you are visible to,
+as detailed below.
+
+== User Visibility
+
+Gerrit has a concept of link:config-gerrit.html#accounts[account visibility]
+which determines what users a given user can see. This visibility configuration
+applies in account search, reviewer suggestion, and when accessing data through
+the link:rest-api-accounts.html#account-endpoints[Account REST endpoints]. If
+you can see a user, you have read access to most of the
+link:rest-api-accounts.html#account-info[AccountInfo] for that user, including
+name and email address. Additional information, including secondary emails, is
+included in AccountInfo if the caller has “Modify Account” permissions.
+
+Additionally, all users on a change (author, cc’d, reviewer) can see each other,
+irrespective of the account visibility settings. For example: Say you are a
+reviewer on a change where user Foo is also a reviewer. Even if by account
+visibility you could not search for Foo, you'd still see their avatar, name,
+and email now because you can see the change; this information is required to
+collaborate on a code review. If Foo wasn't on that change, you could not add
+them because reviewer suggestions would not find them due to the account
+visibility settings.
+
+By default, account visibility on a Gerrit instance is set to `ALL` which allows
+all users to be visible to other users, even anonymous (i.e. unauthenticated)
+users. Depending on your installation type, you may want to change this:
+
+* For completely company-internal Gerrit installations (no external users), the
+`ALL` default may make sense.
+
+* If you work with multiple vendors who have
+access to their own independent sets of repos, `VISIBLE_GROUP` may be more
+appropriate as you wouldn’t want vendor A to see accounts from vendor B.
+
+* For public installations, e.g. for open source projects, you may want to
+change this setting or add a notice for users when they create an account e.g.
+“Most of what you submit on this site, including your email address and name,
+will be visible to others who use this service. You may prefer to use an email
+account specifically for this purpose.” One way to do this is using
+link:config-gerrit.html[`auth.registerPageUrl`] in `gerrit.config`.
+
+== ACLs and User Visibility
+
+User suggestions for changes, when adding a reviewer or cc-ing someone, always
+respect ACLs for that change: only users who can see the change are suggested.
+The suggested users are an intersection of who you can see and who can see the
+change.
+
+Consider the following situation:
+
+* `READ` permission for Registered Users on the host
+* User visibility is set to `VISIBILE_GROUP`, so only users of the same domain can
+ see each other
+* a@foo.com creates change 123
+
+This would mean:
+
+* a@foo.com cannot add b@bar.com to the change because these users cannot see
+ each other due to the user visibility setting.
+* b@bar.com can find change 123
+ because they have READ permission and could add themselves to the change.
+* a@foo.com would then be able to see b@bar.com’s name, avatar, and email on
+ change 123
+
+The only caveat to the above are Private Changes, which are only visible to the
+owner and reviewers; reviewers can only see the change once they are added to
+the change (if ACLs allow them to be added in the first place), not before.
+
+## Right to be Forgotten Limitations
+
+As a source control system, Gerrit has limited abilities to remove personally
+identifiable information. Notably, Gerrit cannot:
+
+* Remove a user's e-mail from all existing commits
+* Remove a user's username
+
+There is also a known
+link:https://bugs.chromium.org/p/gerrit/issues/detail?id=14185[bug] where a
+user's username is stored in metadata for link:user-attention-set.html[Attention
+Set].
+
+
+## Open Source Software Limitations
+
+Gerrit is open-source software licensed under the Apache 2.0 license. 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.
\ No newline at end of file
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 8506cb7..a2dc31f 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -35,7 +35,7 @@
|=============================================================
For change searches (i.e. those using a numerical id, Change-Id, or commit
-SHA1), if the search results in a single change that change will be
+SHA-1), if the search results in a single change that change will be
presented instead of a list.
For more predictable results, use explicit search operators as described
@@ -173,9 +173,9 @@
Changes that have been, or need to be, reviewed by a user in 'GROUP'.
[[commit]]
-commit:'SHA1'::
+commit:'SHA-1'::
+
-Changes where 'SHA1' is one of the patch sets of the change.
+Changes where 'SHA-1' is one of the patch sets of the change.
[[project]]
project:'PROJECT', p:'PROJECT'::
diff --git a/WORKSPACE b/WORKSPACE
index cffbc8d..0d9b06a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -66,8 +66,8 @@
http_archive(
name = "build_bazel_rules_nodejs",
- sha256 = "fcc6dccb39ca88d481224536eb8f9fa754619676c6163f87aa6af94059b02b12",
- urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.2.0/rules_nodejs-3.2.0.tar.gz"],
+ sha256 = "1134ec9b7baee008f1d54f0483049a97e53a57cd3913ec9d6db625549c98395a",
+ urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.4.0/rules_nodejs-3.4.0.tar.gz"],
)
# Golang support for PolyGerrit local dev server.
diff --git a/contrib/find-duplicate-usernames.sh b/contrib/find-duplicate-usernames.sh
new file mode 100755
index 0000000..b59e5be
--- /dev/null
+++ b/contrib/find-duplicate-usernames.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+usage() {
+ f="$(basename -- $0)"
+ cat <<EOF
+Usage:
+ cd /path/to/All-Users.git
+ "$f [username|gerrit|external]"
+
+This script finds duplicate usernames only differing in case in the given
+account schema ("username", "gerrit" or "external") and their respective accountIds.
+EOF
+ exit 1
+}
+
+if [[ "$#" -ne "1" ]] || ! [[ "$1" =~ ^(gerrit|username|external)$ ]]; then
+ usage
+fi
+
+# 1. find lines with user name and subsequent line in external-ids notes branch
+# example output of git grep -A1 "\[externalId \"username:" refs/meta/external-ids:
+# refs/meta/external-ids:00/1d/abd037e437f71d42134e6ad532a06948a2ba:[externalId "username:johndoe"]
+# refs/meta/external-ids:00/1d/abd037e437f71d42134e6ad532a06948a2ba- accountId = 1000815
+# --
+# refs/meta/external-ids:00/1f/0270fc2a6fc3a2439c454c8ab0c75323fdb0:[externalId "username:JohnDoe"]
+# refs/meta/external-ids:00/1f/0270fc2a6fc3a2439c454c8ab0c75323fdb0- accountId = 1000816
+# --
+# 2. remove group separators
+# 3. remove line break between user name and accountId lines
+# 4. unify separators to ":"
+# 5. cut on ":", select username and accountId fields
+# 6. sort case-insensitive
+# 7. flip columns
+# 8. uniq case-insensitive, only show duplicates, avoid comparing first field
+# 9. flip columns back
+git grep -A1 "\[externalId \"$1:" refs/meta/external-ids \
+ | sed -E "/$1/,/accountId/!d" \
+ | paste -d ' ' - - \
+ | tr \"= : \
+ | cut -d: --output-delimiter="" -f 5,8 \
+ | sort -f \
+ | sed -E "s/(.*) (.*)/\2 \1/" \
+ | uniq -Di -f1 \
+ | sed -E "s/(.*) (.*)/\2 \1/"
diff --git a/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/AbandonChange.json b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/AbandonChange.json
new file mode 100644
index 0000000..665cc4d
--- /dev/null
+++ b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/AbandonChange.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "HTTP_SCHEME://HOSTNAME:HTTP_PORT/a/changes/",
+ "number": "NUMBER"
+ }
+]
diff --git a/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/DeleteProject-body.json b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/DeleteProject-body.json
new file mode 100644
index 0000000..488de6d
--- /dev/null
+++ b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/DeleteProject-body.json
@@ -0,0 +1,3 @@
+{
+ "force": "${force_project_deletion}"
+}
diff --git a/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/RestoreChange.json b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/RestoreChange.json
new file mode 100644
index 0000000..665cc4d
--- /dev/null
+++ b/e2e-tests/src/test/resources/data/com/google/gerrit/scenarios/RestoreChange.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "HTTP_SCHEME://HOSTNAME:HTTP_PORT/a/changes/",
+ "number": "NUMBER"
+ }
+]
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/AbandonChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/AbandonChange.scala
new file mode 100644
index 0000000..d387a3e
--- /dev/null
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/AbandonChange.scala
@@ -0,0 +1,71 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.scenarios
+
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef.http
+
+import scala.collection.mutable
+import scala.concurrent.duration.DurationInt
+
+class AbandonChange extends GerritSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).circular
+ private val projectName = className
+ private var numbersCopy: mutable.Queue[Int] = mutable.Queue[Int]()
+ private var createChange: Option[CreateChange] = Some(new CreateChange(projectName))
+
+ override def relativeRuntimeWeight = 10
+
+ def this(createChange: CreateChange) {
+ this()
+ this.createChange = Some(createChange)
+ }
+
+ val test: ScenarioBuilder = scenario(uniqueName)
+ .feed(data)
+ .exec(session => {
+ if (createChange.nonEmpty) {
+ if (numbersCopy.isEmpty) {
+ numbersCopy = createChange.get.numbers.clone()
+ }
+ }
+ session.set(numberKey, numbersCopy.dequeue())
+ })
+ .exec(http(uniqueName).post("${url}${" + numberKey + "}/abandon"))
+
+ private val createProject = new CreateProject(projectName)
+ private val deleteProject = new DeleteProject(projectName)
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(single)
+ ),
+ createChange.get.test.inject(
+ nothingFor(stepWaitTime(createChange.get) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ test.inject(
+ nothingFor(stepWaitTime(this) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(single)
+ ),
+ ).protocols(httpProtocol)
+}
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ApproveChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ApproveChange.scala
index 5e4f671..9a91153 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ApproveChange.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ApproveChange.scala
@@ -40,13 +40,13 @@
if (numbersCopy.isEmpty) {
numbersCopy = createChange.get.numbers.clone()
}
- session.set("number", numbersCopy.dequeue())
+ session.set(numberKey, numbersCopy.dequeue())
} else {
session
}
})
.exec(http(uniqueName)
- .post("${url}${number}/revisions/current/review")
+ .post("${url}${" + numberKey + "}/revisions/current/review")
.body(ElFileBody(body)).asJson)
setUp(
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CheckProjectsCacheFlushEntries.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CheckProjectsCacheFlushEntries.scala
index 96943ce..900702a 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CheckProjectsCacheFlushEntries.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CheckProjectsCacheFlushEntries.scala
@@ -37,7 +37,7 @@
}
})
.exec(http(uniqueName).get("${url}")
- .check(regex("\"" + memKey + "\": (\\d+)")
+ .check(regex("\"" + memKey + "\":(\\d+)")
.is(session => session(entriesKey).as[String])))
setUp(
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala
index b28edb5..fb41075 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala
@@ -24,7 +24,6 @@
class CreateChange extends ProjectSimulation {
private val data: FeederBuilder = jsonFile(resource).convert(keys).circular
- private val numberKey = "_number"
private val weightPerUser = 0.1
private var createBranch: Option[CreateBranch] = None
private var branchesCopy: mutable.Queue[String] = mutable.Queue[String]()
@@ -58,7 +57,7 @@
})
.exec(httpRequest
.body(ElFileBody(body)).asJson
- .check(regex("\"" + numberKey + "\":(\\d+),").saveAs(numberKey)))
+ .check(regex("\"_" + numberKey + "\":(\\d+),").saveAs(numberKey)))
.exec(session => {
number = session(numberKey).as[Int]
numbers += number
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala
index e47108f..743219f 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala
@@ -34,12 +34,12 @@
.feed(data)
.exec(session => {
if (createChange.nonEmpty) {
- session.set("number", createChange.get.numbers.dequeue())
+ session.set(numberKey, createChange.get.numbers.dequeue())
} else {
session
}
})
- .exec(http(uniqueName).delete("${url}${number}"))
+ .exec(http(uniqueName).delete("${url}${" + numberKey + "}"))
setUp(
test.inject(
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteProject.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteProject.scala
index 1752634..eb4df30 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteProject.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteProject.scala
@@ -20,6 +20,7 @@
class DeleteProject extends ProjectSimulation {
private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+ private val forceKey = "force_project_deletion"
def this(projectName: String) {
this()
@@ -28,7 +29,10 @@
val test: ScenarioBuilder = scenario(uniqueName)
.feed(data)
- .exec(httpRequest)
+ .exec(session => {
+ session.set(forceKey, getProperty(forceKey, "false"))
+ })
+ .exec(httpRequest.body(ElFileBody(body)).asJson)
setUp(
test.inject(
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala
index b11c87c..c199dd9 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala
@@ -23,6 +23,8 @@
class GerritSimulation extends Simulation {
implicit val conf: GatlingGitConfiguration = GatlingGitConfiguration()
+ protected val numberKey: String = "number"
+
private val packageName = getClass.getPackage.getName
private val path = packageName.replaceAllLiterally(".", "/")
@@ -64,9 +66,9 @@
protected val keys: PartialFunction[(String, Any), Any] = {
case ("entries", entries) =>
replaceProperty("projects_entries", "1", entries.toString)
- case ("number", number) =>
- val precedes = replaceKeyWith("_number", 0, number.toString)
- replaceProperty("number", 1, precedes)
+ case (`numberKey`, number) =>
+ val precedes = replaceKeyWith("_" + numberKey, 0, number.toString)
+ replaceProperty(numberKey, 1, precedes)
case ("parent", parent) =>
replaceProperty("parent", "All-Projects", parent.toString)
case ("project", project) =>
@@ -90,6 +92,11 @@
}
protected def replaceProperty(term: String, default: Any, in: String): String = {
+ val value = getProperty(term, default)
+ replaceKeyWith(term, value, in)
+ }
+
+ protected def getProperty(term: String, default: Any): String = {
val property = packageName + "." + term
var value = default
default match {
@@ -101,7 +108,7 @@
case _: Integer =>
value = Integer.getInteger(property, default.asInstanceOf[Integer])
}
- replaceKeyWith(term, value, in)
+ value.toString
}
protected def replaceKeyWith(term: String, value: Any, in: String): String = {
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetMasterBranchRevision.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetMasterBranchRevision.scala
index 1137ad5..f2236d1 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetMasterBranchRevision.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetMasterBranchRevision.scala
@@ -23,7 +23,7 @@
private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
var revision: Option[String] = None
val revisionKey = "revision"
- val revisionPattern: String = "\"" + revisionKey + "\": \"(.+)\""
+ val revisionPattern: String = "\"" + revisionKey + "\":\"(.+)\""
val test: ScenarioBuilder = scenario(uniqueName)
.feed(data)
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetProjectsCacheEntries.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetProjectsCacheEntries.scala
index 266c0b9..0bb3afb 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetProjectsCacheEntries.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GetProjectsCacheEntries.scala
@@ -30,7 +30,7 @@
val test: ScenarioBuilder = scenario(uniqueName)
.feed(data)
.exec(http(uniqueName).get("${url}")
- .check(regex("\"" + memKey + "\": (\\d+)").saveAs(entriesKey)))
+ .check(regex("\"" + memKey + "\":(\\d+)").saveAs(entriesKey)))
.exec(session => {
if (consumer.nonEmpty) {
consumer.get.entriesBeforeFlush(session(entriesKey).as[Int])
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/RestoreChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/RestoreChange.scala
new file mode 100644
index 0000000..81096b0
--- /dev/null
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/RestoreChange.scala
@@ -0,0 +1,74 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.scenarios
+
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef.http
+
+import scala.collection.mutable
+import scala.concurrent.duration.DurationInt
+
+class RestoreChange extends GerritSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).circular
+ private val projectName = className
+ private var numbersCopy: mutable.Queue[Int] = mutable.Queue[Int]()
+
+ override def relativeRuntimeWeight = 10
+
+ private val test: ScenarioBuilder = scenario(uniqueName)
+ .feed(data)
+ .exec(session => {
+ if (numbersCopy.isEmpty) {
+ numbersCopy = createChange.numbers.clone()
+ }
+ session.set(numberKey, numbersCopy.dequeue())
+ }
+ ).exec(http(uniqueName).post("${url}${" + numberKey + "}/restore"))
+
+ private val createProject = new CreateProject(projectName)
+ private val createChange = new CreateChange(projectName)
+ private val abandonChange = new AbandonChange(createChange)
+ private val deleteChange = new DeleteChange(createChange)
+ private val deleteProject = new DeleteProject(projectName)
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(single)
+ ),
+ createChange.test.inject(
+ nothingFor(stepWaitTime(createChange) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ abandonChange.test.inject(
+ nothingFor(stepWaitTime(abandonChange) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ test.inject(
+ nothingFor(stepWaitTime(this) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ deleteChange.test.inject(
+ nothingFor(stepWaitTime(deleteChange) seconds),
+ atOnceUsers(numberOfUsers)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(single)
+ ),
+ ).protocols(httpProtocol)
+}
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChange.scala
index 067496a..20be28a 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChange.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChange.scala
@@ -36,9 +36,9 @@
val test: ScenarioBuilder = scenario(uniqueName)
.feed(data)
.exec(session => {
- session.set("number", createChange.number)
+ session.set(numberKey, createChange.number)
})
- .exec(http(uniqueName).post("${url}${number}/submit"))
+ .exec(http(uniqueName).post("${url}${" + numberKey + "}/submit"))
private val createProject = new CreateProject(projectName)
private val approveChange = new ApproveChange(createChange)
diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChangeInBranch.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChangeInBranch.scala
index 1b88503..9e1431b 100644
--- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChangeInBranch.scala
+++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/SubmitChangeInBranch.scala
@@ -35,9 +35,9 @@
if (changesCopy.isEmpty) {
changesCopy = createChange.numbers.clone()
}
- session.set("number", changesCopy.dequeue())
+ session.set(numberKey, changesCopy.dequeue())
})
- .exec(http(uniqueName).post("${url}${number}/submit"))
+ .exec(http(uniqueName).post("${url}${" + numberKey + "}/submit"))
private val createProject = new CreateProject(projectName)
private val createBranch = new CreateBranch(projectName)
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 5b27088..b05050d 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -48,6 +48,7 @@
import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.acceptance.testsuite.request.SshSessionFactory;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccessSection;
import com.google.gerrit.entities.Account;
@@ -59,6 +60,7 @@
import com.google.gerrit.entities.EmailHeader;
import com.google.gerrit.entities.GroupDescription;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.LabelValue;
@@ -74,6 +76,7 @@
import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.api.changes.SubmittedTogetherInfo;
import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.client.InheritableBoolean;
@@ -114,7 +117,6 @@
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.index.account.AccountIndex;
import com.google.gerrit.server.index.account.AccountIndexCollection;
@@ -143,7 +145,6 @@
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Provider;
-import com.jcraft.jsch.KeyPair;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -155,6 +156,7 @@
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.security.KeyPair;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
@@ -174,6 +176,7 @@
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
@@ -561,7 +564,7 @@
&& (adminSshSession == null || userSshSession == null)) {
// Create Ssh sessions
KeyPair adminKeyPair = sshKeys.getKeyPair(admin);
- GitUtil.initSsh(adminKeyPair);
+ SshSessionFactory.initSsh(adminKeyPair);
Context ctx = newRequestContext(user);
atrScope.set(ctx);
userSshSession = ctx.getSession();
@@ -583,6 +586,7 @@
ProjectInput in = new ProjectInput();
TestProjectInput ann = description.getAnnotation(TestProjectInput.class);
in.name = name("project");
+ in.branches = ImmutableList.of(Constants.R_HEADS + Constants.MASTER);
if (ann != null) {
in.parent = Strings.emptyToNull(ann.parent());
in.description = Strings.emptyToNull(ann.description());
@@ -1349,6 +1353,16 @@
assertThat(rule.getMax()).isEqualTo(expectedMax);
}
+ protected void assertHead(String projectName, String expectedRef) throws Exception {
+ // Assert gerrit's project head points to the correct branch
+ assertThat(getProjectBranches(projectName).get(Constants.HEAD).revision)
+ .isEqualTo(RefNames.shortName(expectedRef));
+ // Assert git head points to the correct branch
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
+ assertThat(repo.exactRef(Constants.HEAD).getTarget().getName()).isEqualTo(expectedRef);
+ }
+ }
+
protected InternalGroup group(AccountGroup.UUID groupUuid) {
InternalGroup group = groupCache.get(groupUuid).orElse(null);
assertWithMessage(groupUuid.get()).that(group).isNotNull();
@@ -1622,6 +1636,12 @@
return comments;
}
+ protected ImmutableMap<String, BranchInfo> getProjectBranches(String projectName)
+ throws RestApiException {
+ return gApi.projects().name(projectName).branches().get().stream()
+ .collect(ImmutableMap.toImmutableMap(branch -> branch.ref, branch -> branch));
+ }
+
protected AutoCloseable installPlugin(String pluginName, Class<? extends Module> sysModuleClass)
throws Exception {
return installPlugin(pluginName, sysModuleClass, null, null);
diff --git a/java/com/google/gerrit/acceptance/AccountCreator.java b/java/com/google/gerrit/acceptance/AccountCreator.java
index 6897488..1b0954e 100644
--- a/java/com/google/gerrit/acceptance/AccountCreator.java
+++ b/java/com/google/gerrit/acceptance/AccountCreator.java
@@ -22,13 +22,13 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.group.db.InternalGroupUpdate;
import com.google.gerrit.server.notedb.Sequences;
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index 28f67b8..5ee1a08 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -40,6 +40,7 @@
"//lib:guava-retrying",
"//lib:jgit",
"//lib:jgit-ssh-jsch",
+ "//lib:jgit-ssh-apache",
"//lib:jsch",
"//lib/commons:compress",
"//lib/commons:lang",
@@ -52,6 +53,7 @@
"//lib/mina:sshd",
"//lib:guava",
"//lib/bouncycastle:bcpg",
+ "//lib/bouncycastle:bcpkix",
"//lib/bouncycastle:bcprov",
"//prolog:gerrit-prolog-common",
]
diff --git a/java/com/google/gerrit/acceptance/ExtensionRegistry.java b/java/com/google/gerrit/acceptance/ExtensionRegistry.java
index 5d01dcb..35f8ce6 100644
--- a/java/com/google/gerrit/acceptance/ExtensionRegistry.java
+++ b/java/com/google/gerrit/acceptance/ExtensionRegistry.java
@@ -39,6 +39,7 @@
import com.google.gerrit.server.change.ChangeETagComputation;
import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.git.ChangeMessageModifier;
+import com.google.gerrit.server.git.receive.PluginPushOption;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.OnSubmitValidationListener;
import com.google.gerrit.server.git.validators.RefOperationValidationListener;
@@ -84,6 +85,7 @@
private final DynamicMap<CapabilityDefinition> capabilityDefinitions;
private final DynamicMap<PluginProjectPermissionDefinition> pluginProjectPermissionDefinitions;
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
+ private final DynamicSet<PluginPushOption> pluginPushOptions;
private final DynamicSet<OnPostReview> onPostReviews;
@Inject
@@ -116,6 +118,7 @@
DynamicMap<CapabilityDefinition> capabilityDefinitions,
DynamicMap<PluginProjectPermissionDefinition> pluginProjectPermissionDefinitions,
DynamicMap<ProjectConfigEntry> pluginConfigEntries,
+ DynamicSet<PluginPushOption> pluginPushOption,
DynamicSet<OnPostReview> onPostReviews) {
this.accountIndexedListeners = accountIndexedListeners;
this.changeIndexedListeners = changeIndexedListeners;
@@ -145,6 +148,7 @@
this.capabilityDefinitions = capabilityDefinitions;
this.pluginProjectPermissionDefinitions = pluginProjectPermissionDefinitions;
this.pluginConfigEntries = pluginConfigEntries;
+ this.pluginPushOptions = pluginPushOption;
this.onPostReviews = onPostReviews;
}
@@ -274,6 +278,10 @@
return add(pluginConfigEntries, pluginConfigEntry, exportName);
}
+ public Registration add(PluginPushOption pluginPushOption) {
+ return add(pluginPushOptions, pluginPushOption);
+ }
+
public Registration add(OnPostReview onPostReview) {
return add(onPostReviews, onPostReview);
}
diff --git a/java/com/google/gerrit/acceptance/GitUtil.java b/java/com/google/gerrit/acceptance/GitUtil.java
index ae72793..94d329d 100644
--- a/java/com/google/gerrit/acceptance/GitUtil.java
+++ b/java/com/google/gerrit/acceptance/GitUtil.java
@@ -20,17 +20,11 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
-import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.entities.Project;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.KeyPair;
-import com.jcraft.jsch.Session;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
-import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jgit.api.FetchCommand;
@@ -47,41 +41,15 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchResult;
-import org.eclipse.jgit.transport.JschConfigSessionFactory;
-import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteRefUpdate;
-import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.util.FS;
public class GitUtil {
private static final AtomicInteger testRepoCount = new AtomicInteger();
private static final int TEST_REPO_WINDOW_DAYS = 2;
- public static void initSsh(KeyPair keyPair) {
- final Properties config = new Properties();
- config.put("StrictHostKeyChecking", "no");
- JSch.setConfig(config);
-
- // register a JschConfigSessionFactory that adds the private key as identity
- // to the JSch instance of JGit so that SSH communication via JGit can
- // succeed
- SshSessionFactory.setInstance(
- new JschConfigSessionFactory() {
- @Override
- protected void configure(Host hc, Session session) {
- try {
- final JSch jsch = getJSch(hc, FS.DETECTED);
- jsch.addIdentity(
- "KeyPair", TestSshKeys.privateKey(keyPair), keyPair.getPublicKeyBlob(), null);
- } catch (JSchException e) {
- throw new RuntimeException(e);
- }
- }
- });
- }
-
/**
* Create a new {@link TestRepository} with a distinct commit clock.
*
diff --git a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index a3207e2..de9a43d 100644
--- a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -20,7 +20,6 @@
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePath;
@@ -64,7 +63,7 @@
bind(InMemoryRepositoryManager.class).in(SINGLETON);
}
- bind(MetricMaker.class).to(DisabledMetricMaker.class);
+ bind(MetricMaker.class).to(TestMetricMaker.class);
listener().to(CreateSchema.class);
diff --git a/java/com/google/gerrit/acceptance/InProcessProtocol.java b/java/com/google/gerrit/acceptance/InProcessProtocol.java
index 2a3a35f..83c63f9 100644
--- a/java/com/google/gerrit/acceptance/InProcessProtocol.java
+++ b/java/com/google/gerrit/acceptance/InProcessProtocol.java
@@ -338,7 +338,7 @@
.project(req.project)
.availableTokens(REPOSITORY_SIZE_GROUP);
availableTokens.throwOnError();
- availableTokens.availableTokens().ifPresent(v -> rp.setMaxObjectSizeLimit(v));
+ availableTokens.availableTokens().ifPresent(rp::setMaxPackSizeLimit);
ImmutableList<PostReceiveHook> hooks =
ImmutableList.<PostReceiveHook>builder()
diff --git a/java/com/google/gerrit/acceptance/PushOneCommit.java b/java/com/google/gerrit/acceptance/PushOneCommit.java
index 4215255..67e26ec 100644
--- a/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -47,6 +47,7 @@
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -294,6 +295,23 @@
return this;
}
+ public PushOneCommit addGitSubmodule(String modulePath, ObjectId commitId) {
+ commitBuilder.edit(
+ new PathEdit(modulePath) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(commitId);
+ }
+ });
+ return this;
+ }
+
+ public PushOneCommit rmFile(String filename) {
+ commitBuilder.rm(filename);
+ return this;
+ }
+
public Result to(String ref) throws Exception {
for (Map.Entry<String, String> e : files.entrySet()) {
commitBuilder.add(e.getKey(), e.getValue());
diff --git a/java/com/google/gerrit/acceptance/SshSession.java b/java/com/google/gerrit/acceptance/SshSession.java
index 6698657..054e523 100644
--- a/java/com/google/gerrit/acceptance/SshSession.java
+++ b/java/com/google/gerrit/acceptance/SshSession.java
@@ -14,27 +14,18 @@
package com.google.gerrit.acceptance;
-import static com.google.common.base.Preconditions.checkState;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.acceptance.testsuite.account.TestAccount;
import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
-import com.jcraft.jsch.ChannelExec;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.KeyPair;
-import com.jcraft.jsch.Session;
-import java.io.InputStream;
import java.net.InetSocketAddress;
-import java.util.Scanner;
-public class SshSession {
- private final TestSshKeys sshKeys;
- private final InetSocketAddress addr;
- private final TestAccount account;
- private Session session;
- private String error;
+public abstract class SshSession {
+ protected final TestSshKeys sshKeys;
+ protected final InetSocketAddress addr;
+ protected final TestAccount account;
+ protected String error;
public SshSession(TestSshKeys sshKeys, InetSocketAddress addr, TestAccount account) {
this.sshKeys = sshKeys;
@@ -42,44 +33,13 @@
this.account = account;
}
- public void open() throws Exception {
- getSession();
- }
+ public abstract void open() throws Exception;
- @SuppressWarnings("resource")
- public String exec(String command) throws Exception {
- ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
- try {
- channel.setCommand(command);
- InputStream in = channel.getInputStream();
- InputStream err = channel.getErrStream();
- channel.connect();
+ public abstract void close();
- Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
- error = s.hasNext() ? s.next() : null;
+ public abstract String exec(String command) throws Exception;
- s = new Scanner(in, UTF_8.name()).useDelimiter("\\A");
- return s.hasNext() ? s.next() : "";
- } finally {
- channel.disconnect();
- }
- }
-
- @SuppressWarnings("resource")
- public int execAndReturnStatus(String command) throws Exception {
- ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
- try {
- channel.setCommand(command);
- InputStream err = channel.getErrStream();
- channel.connect();
-
- Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
- error = s.hasNext() ? s.next() : null;
- return channel.getExitStatus();
- } finally {
- channel.disconnect();
- }
- }
+ public abstract int execAndReturnStatus(String command) throws Exception;
private boolean hasError() {
return error != null;
@@ -102,46 +62,23 @@
assertThat(getError()).contains(error);
}
- public void close() {
- if (session != null) {
- session.disconnect();
- session = null;
- }
- }
-
- private Session getSession() throws Exception {
- if (session == null) {
- KeyPair keyPair = sshKeys.getKeyPair(account);
- JSch jsch = new JSch();
- jsch.addIdentity(
- "KeyPair", TestSshKeys.privateKey(keyPair), keyPair.getPublicKeyBlob(), null);
- String username =
- account
- .username()
- .orElseThrow(
- () ->
- new IllegalStateException(
- "account " + account.accountId() + " must have a username to use SSH"));
- session = jsch.getSession(username, addr.getAddress().getHostAddress(), addr.getPort());
- session.setConfig("StrictHostKeyChecking", "no");
- session.connect();
- }
- return session;
- }
-
public String getUrl() {
- checkState(session != null, "session must be opened");
StringBuilder b = new StringBuilder();
b.append("ssh://");
- b.append(session.getUserName());
+ b.append(account.username().get());
b.append("@");
- b.append(session.getHost());
+ b.append(addr.getAddress().getHostAddress());
b.append(":");
- b.append(session.getPort());
+ b.append(addr.getPort());
return b.toString();
}
- public TestAccount getAccount() {
- return account;
+ protected String getUsername() {
+ return account
+ .username()
+ .orElseThrow(
+ () ->
+ new IllegalStateException(
+ "account " + account.accountId() + " must have a username to use SSH"));
}
}
diff --git a/java/com/google/gerrit/acceptance/SshSessionJsch.java b/java/com/google/gerrit/acceptance/SshSessionJsch.java
new file mode 100644
index 0000000..86cc438
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/SshSessionJsch.java
@@ -0,0 +1,156 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.gerrit.acceptance.testsuite.account.TestAccount;
+import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.InetSocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Properties;
+import java.util.Scanner;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.eclipse.jgit.transport.JschConfigSessionFactory;
+import org.eclipse.jgit.transport.OpenSshConfig.Host;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.util.FS;
+
+public class SshSessionJsch extends SshSession {
+
+ private Session session;
+
+ public static void initClient(KeyPair keyPair) {
+ Properties config = new Properties();
+ config.put("StrictHostKeyChecking", "no");
+ JSch.setConfig(config);
+
+ // register a JschConfigSessionFactory that adds the private key as identity
+ // to the JSch instance of JGit so that SSH communication via JGit can
+ // succeed
+ SshSessionFactory.setInstance(
+ new JschConfigSessionFactory() {
+ @Override
+ protected void configure(Host hc, Session session) {
+ try {
+ JSch jsch = getJSch(hc, FS.DETECTED);
+ jsch.addIdentity(
+ "KeyPair", privateKey(keyPair), TestSshKeys.publicKeyBlob(keyPair), null);
+ } catch (JSchException | GeneralSecurityException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ public static KeyPairGenerator initKeyPairGenerator() throws NoSuchAlgorithmException {
+ KeyPairGenerator gen;
+ gen = KeyPairGenerator.getInstance("RSA");
+ gen.initialize(512, new SecureRandom());
+ return gen;
+ }
+
+ public SshSessionJsch(TestSshKeys sshKeys, InetSocketAddress addr, TestAccount account) {
+ super(sshKeys, addr, account);
+ }
+
+ @Override
+ public void open() throws Exception {
+ getJschSession();
+ }
+
+ @Override
+ public void close() {
+ if (session != null) {
+ session.disconnect();
+ session = null;
+ }
+ }
+
+ @SuppressWarnings("resource")
+ @Override
+ public String exec(String command) throws Exception {
+ ChannelExec channel = (ChannelExec) getJschSession().openChannel("exec");
+ try {
+ channel.setCommand(command);
+ InputStream in = channel.getInputStream();
+ InputStream err = channel.getErrStream();
+ channel.connect();
+
+ Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
+ error = s.hasNext() ? s.next() : null;
+
+ s = new Scanner(in, UTF_8.name()).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ } finally {
+ channel.disconnect();
+ }
+ }
+
+ @SuppressWarnings("resource")
+ @Override
+ public int execAndReturnStatus(String command) throws Exception {
+ ChannelExec channel = (ChannelExec) getJschSession().openChannel("exec");
+ try {
+ channel.setCommand(command);
+ InputStream err = channel.getErrStream();
+ channel.connect();
+
+ Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
+ error = s.hasNext() ? s.next() : null;
+ return channel.getExitStatus();
+ } finally {
+ channel.disconnect();
+ }
+ }
+
+ private Session getJschSession() throws Exception {
+ if (session == null) {
+ KeyPair keyPair = sshKeys.getKeyPair(account);
+ JSch jsch = new JSch();
+ jsch.addIdentity("KeyPair", privateKey(keyPair), TestSshKeys.publicKeyBlob(keyPair), null);
+ String username = getUsername();
+ session = jsch.getSession(username, addr.getAddress().getHostAddress(), addr.getPort());
+ session.setConfig("StrictHostKeyChecking", "no");
+ session.connect();
+ }
+ return session;
+ }
+
+ private static byte[] privateKey(KeyPair keyPair) throws IOException {
+ // unencrypted form of PKCS#8 file
+ JcaPKCS8Generator gen1 = new JcaPKCS8Generator(keyPair.getPrivate(), null);
+ PemObject obj1 = gen1.generate();
+ StringWriter sw1 = new StringWriter();
+ try (JcaPEMWriter pw = new JcaPEMWriter(sw1)) {
+ pw.writeObject(obj1);
+ }
+ return sw1.toString().getBytes(US_ASCII.name());
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/SshSessionMina.java b/java/com/google/gerrit/acceptance/SshSessionMina.java
new file mode 100644
index 0000000..4514f44
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/SshSessionMina.java
@@ -0,0 +1,170 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance;
+
+import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.io.CharSink;
+import com.google.common.io.Files;
+import com.google.common.io.MoreFiles;
+import com.google.gerrit.acceptance.testsuite.account.TestAccount;
+import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPairGenerator;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import java.util.Scanner;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.sshd.DefaultProxyDataFactory;
+import org.eclipse.jgit.transport.sshd.JGitKeyCache;
+import org.eclipse.jgit.transport.sshd.SshdSession;
+import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
+import org.eclipse.jgit.util.FS;
+
+public class SshSessionMina extends SshSession {
+ private static final int TIMEOUT = 100000;
+
+ private SshdSession session;
+
+ public static void initClient() {
+ JGitKeyCache keyCache = new JGitKeyCache();
+ SshdSessionFactory factory = new SshdSessionFactory(keyCache, new DefaultProxyDataFactory());
+ SshSessionFactory.setInstance(factory);
+ }
+
+ public static KeyPairGenerator initKeyPairGenerator()
+ throws GeneralSecurityException, InvalidKeySpecException, InvalidAlgorithmParameterException {
+ int size = 256;
+ KeyPairGenerator gen = SecurityUtils.getKeyPairGenerator(KeyUtils.EC_ALGORITHM);
+ ECCurves curve = ECCurves.fromCurveSize(size);
+ if (curve == null) {
+ throw new InvalidKeySpecException("Unknown curve for key size=" + size);
+ }
+ gen.initialize(curve.getParameters());
+ return gen;
+ }
+
+ public SshSessionMina(TestSshKeys sshKeys, InetSocketAddress addr, TestAccount account) {
+ super(sshKeys, addr, account);
+ }
+
+ @Override
+ public void open() throws Exception {
+ getMinaSession();
+ }
+
+ @Override
+ public void close() {
+ if (session != null) {
+ session.disconnect();
+ session = null;
+ }
+ }
+
+ @SuppressWarnings("resource")
+ @Override
+ public String exec(String command) throws Exception {
+ Process process = getMinaSession().exec(command, TIMEOUT);
+ InputStream in = process.getInputStream();
+ InputStream err = process.getErrorStream();
+
+ Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
+ error = s.hasNext() ? s.next() : null;
+
+ s = new Scanner(in, UTF_8.name()).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+ @SuppressWarnings("resource")
+ @Override
+ public int execAndReturnStatus(String command) throws Exception {
+ Process process = getMinaSession().exec(command, 0);
+ InputStream in = process.getInputStream();
+ InputStream err = process.getErrorStream();
+
+ Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
+ error = s.hasNext() ? s.next() : null;
+
+ s = new Scanner(in, UTF_8.name()).useDelimiter("\\A");
+ try {
+ return process.exitValue();
+ } catch (IllegalThreadStateException e) {
+ // SSH command was interrupted
+ return -1;
+ }
+ }
+
+ private SshdSession getMinaSession() throws Exception {
+ if (session == null) {
+ String username = getUsername();
+
+ URIish uri =
+ new URIish(
+ "ssh://"
+ + username
+ + "@"
+ + addr.getAddress().getHostAddress()
+ + ":"
+ + addr.getPort());
+
+ // TODO(davido): Switch to memory only key resolving mode.
+ File userhome = Files.createTempDir();
+
+ FS fs = FS.DETECTED.setUserHome(userhome);
+ File sshDir = new File(userhome, ".ssh");
+ sshDir.mkdir();
+ OpenSSHKeyPairResourceWriter keyPairWriter = new OpenSSHKeyPairResourceWriter();
+ try (OutputStream out = new FileOutputStream(new File(sshDir, "id_ecdsa"))) {
+ keyPairWriter.writePrivateKey(sshKeys.getKeyPair(account), null, null, out);
+ }
+
+ // TODO(davido): Disable programmatically host key checking: "StrictHostKeyChecking: no" mode.
+ CharSink configFile = Files.asCharSink(new File(sshDir, "config"), UTF_8);
+ configFile.writeLines(Arrays.asList("Host *", "StrictHostKeyChecking no"));
+
+ JGitKeyCache keyCache = new JGitKeyCache();
+ try (SshdSessionFactory factory =
+ new SshdSessionFactory(keyCache, new DefaultProxyDataFactory())) {
+ factory.setHomeDirectory(userhome);
+ factory.setSshDirectory(sshDir);
+
+ session = factory.getSession(uri, null, fs, TIMEOUT);
+
+ session.addCloseListener(
+ future -> {
+ try {
+ MoreFiles.deleteRecursively(userhome.toPath(), ALLOW_INSECURE);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+ }
+ return session;
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/TestMetricMaker.java b/java/com/google/gerrit/acceptance/TestMetricMaker.java
new file mode 100644
index 0000000..d60ef1a
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/TestMetricMaker.java
@@ -0,0 +1,78 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.inject.Singleton;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.lang.mutable.MutableLong;
+
+/**
+ * {@link com.google.gerrit.metrics.MetricMaker} to be bound in tests.
+ *
+ * <p>Records how often {@link Counter0} metrics are invoked. Metrics of other types are not
+ * recorded.
+ *
+ * <p>Allows test to check how much a {@link Counter0} metrics is increased by an operation.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * public class MyTest extends AbstractDaemonTest {
+ * @Inject private TestMetricMaker testMetricMaker;
+ *
+ * ...
+ *
+ * @Test
+ * public void testFoo() throws Exception {
+ * testMetricMaker.reset();
+ * doSomething();
+ * assertThat(testMetricMaker.getCount("foo/bar_count")).isEqualsTo(1);
+ * }
+ * }
+ * </pre>
+ */
+@Singleton
+public class TestMetricMaker extends DisabledMetricMaker {
+ private final Map<String, MutableLong> counts = new HashMap<>();
+
+ public long getCount(String counter0Name) {
+ return get(counter0Name).longValue();
+ }
+
+ public void reset() {
+ counts.clear();
+ }
+
+ private MutableLong get(String counter0Name) {
+ return counts.computeIfAbsent(counter0Name, name -> new MutableLong(0));
+ }
+
+ @Override
+ public Counter0 newCounter(String name, Description desc) {
+ return new Counter0() {
+ @Override
+ public void incrementBy(long value) {
+ get(name).add(value);
+ }
+
+ @Override
+ public void remove() {}
+ };
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/TestSshKeys.java b/java/com/google/gerrit/acceptance/testsuite/account/TestSshKeys.java
index 6c95360..277d219 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/TestSshKeys.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/TestSshKeys.java
@@ -18,19 +18,20 @@
import static java.nio.charset.StandardCharsets.US_ASCII;
import com.google.gerrit.acceptance.SshEnabled;
+import com.google.gerrit.acceptance.testsuite.request.SshSessionFactory;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.KeyPair;
import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;
+import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter;
@Singleton
public class TestSshKeys {
@@ -86,27 +87,26 @@
private KeyPair createKeyPair(Account.Id accountId, String username, @Nullable String email)
throws Exception {
- KeyPair keyPair = genSshKey();
+ KeyPair keyPair = SshSessionFactory.genSshKey();
authorizedKeys.addKey(accountId, publicKey(keyPair, email));
sshKeyCache.evict(username);
return keyPair;
}
- public static KeyPair genSshKey() throws JSchException {
- JSch jsch = new JSch();
- return KeyPair.genKeyPair(jsch, KeyPair.ECDSA, 256);
- }
-
public static String publicKey(KeyPair sshKey, @Nullable String comment)
- throws UnsupportedEncodingException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- sshKey.writePublicKey(out, comment);
- return out.toString(US_ASCII.name()).trim();
+ throws IOException, GeneralSecurityException {
+ return preparePublicKey(sshKey, comment).toString(US_ASCII.name()).trim();
}
- public static byte[] privateKey(KeyPair keyPair) {
+ public static byte[] publicKeyBlob(KeyPair sshKey) throws IOException, GeneralSecurityException {
+ return preparePublicKey(sshKey, null).toByteArray();
+ }
+
+ private static ByteArrayOutputStream preparePublicKey(KeyPair sshKey, String comment)
+ throws IOException, GeneralSecurityException {
+ OpenSSHKeyPairResourceWriter keyPairWriter = new OpenSSHKeyPairResourceWriter();
ByteArrayOutputStream out = new ByteArrayOutputStream();
- keyPair.writePrivateKey(out);
- return out.toByteArray();
+ keyPairWriter.writePublicKey(sshKey, comment, out);
+ return out;
}
}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java
index 21d1232..cde5134 100644
--- a/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java
@@ -17,12 +17,12 @@
import static com.google.common.base.Preconditions.checkState;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.GroupUuid;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.group.db.InternalGroupCreation;
diff --git a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
index f6e5de3..e7354ab 100644
--- a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImpl.java
@@ -138,6 +138,9 @@
throws IOException, ConfigInvalidException {
try (MetaDataUpdate metaDataUpdate = metaDataUpdateFactory.create(nameKey)) {
ProjectConfig projectConfig = projectConfigFactory.read(metaDataUpdate);
+ if (projectUpdate.removeAllAccessSections()) {
+ projectConfig.getAccessSections().forEach(as -> projectConfig.remove(as));
+ }
removePermissions(projectConfig, projectUpdate.removedPermissions());
addCapabilities(projectConfig, projectUpdate.addedCapabilities());
addPermissions(projectConfig, projectUpdate.addedPermissions());
diff --git a/java/com/google/gerrit/acceptance/testsuite/project/TestProjectUpdate.java b/java/com/google/gerrit/acceptance/testsuite/project/TestProjectUpdate.java
index ea20931..9a9a21a 100644
--- a/java/com/google/gerrit/acceptance/testsuite/project/TestProjectUpdate.java
+++ b/java/com/google/gerrit/acceptance/testsuite/project/TestProjectUpdate.java
@@ -294,7 +294,8 @@
return new AutoValue_TestProjectUpdate.Builder()
.nameKey(nameKey)
.allProjectsName(allProjectsName)
- .projectUpdater(projectUpdater);
+ .projectUpdater(projectUpdater)
+ .removeAllAccessSections(false);
}
/** Builder for {@link TestProjectUpdate}. */
@@ -314,6 +315,16 @@
abstract ImmutableMap.Builder<TestPermissionKey, Boolean> exclusiveGroupPermissionsBuilder();
+ abstract Builder removeAllAccessSections(boolean value);
+
+ /**
+ * Removes all access sections. Useful when testing against a specific set of access sections or
+ * permissions.
+ */
+ public Builder removeAllAccessSections() {
+ return removeAllAccessSections(true);
+ }
+
/** Adds a permission to be included in this update. */
public Builder add(TestPermission testPermission) {
addedPermissionsBuilder().add(testPermission);
@@ -418,6 +429,8 @@
abstract ThrowingConsumer<TestProjectUpdate> projectUpdater();
+ abstract boolean removeAllAccessSections();
+
boolean hasCapabilityUpdates() {
return !addedCapabilities().isEmpty()
|| removedPermissions().stream().anyMatch(k -> k.section().equals(GLOBAL_CAPABILITIES));
diff --git a/java/com/google/gerrit/acceptance/testsuite/request/RequestScopeOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/request/RequestScopeOperationsImpl.java
index db730a6..895c7a0 100644
--- a/java/com/google/gerrit/acceptance/testsuite/request/RequestScopeOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/request/RequestScopeOperationsImpl.java
@@ -19,7 +19,6 @@
import com.google.gerrit.acceptance.AcceptanceTestRequestScope;
import com.google.gerrit.acceptance.GerritServer.TestSshServerAddress;
-import com.google.gerrit.acceptance.SshSession;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.account.TestAccount;
import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
@@ -82,7 +81,7 @@
public AcceptanceTestRequestScope.Context setApiUser(TestAccount testAccount) {
return atrScope.set(
atrScope.newContext(
- new SshSession(testSshKeys, sshAddress, testAccount),
+ SshSessionFactory.createSession(testSshKeys, sshAddress, testAccount),
createIdentifiedUser(testAccount.accountId())));
}
diff --git a/java/com/google/gerrit/acceptance/testsuite/request/SshSessionFactory.java b/java/com/google/gerrit/acceptance/testsuite/request/SshSessionFactory.java
new file mode 100644
index 0000000..d5dd28a
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/request/SshSessionFactory.java
@@ -0,0 +1,52 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.testsuite.request;
+
+import static com.google.gerrit.server.config.SshClientImplementation.getFromEnvironment;
+
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.SshSessionJsch;
+import com.google.gerrit.acceptance.SshSessionMina;
+import com.google.gerrit.acceptance.testsuite.account.TestAccount;
+import com.google.gerrit.acceptance.testsuite.account.TestSshKeys;
+import java.net.InetSocketAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+
+public class SshSessionFactory {
+ public static SshSession createSession(
+ TestSshKeys testSshKeys, InetSocketAddress sshAddress, TestAccount testAccount) {
+ return getFromEnvironment().isMina()
+ ? new SshSessionMina(testSshKeys, sshAddress, testAccount)
+ : new SshSessionJsch(testSshKeys, sshAddress, testAccount);
+ }
+
+ public static void initSsh(KeyPair keyPair) {
+ if (getFromEnvironment().isMina()) {
+ SshSessionMina.initClient();
+ } else {
+ SshSessionJsch.initClient(keyPair);
+ }
+ }
+
+ private SshSessionFactory() {}
+
+ public static KeyPair genSshKey() throws GeneralSecurityException {
+ return (getFromEnvironment().isMina()
+ ? SshSessionMina.initKeyPairGenerator()
+ : SshSessionJsch.initKeyPairGenerator())
+ .generateKeyPair();
+ }
+}
diff --git a/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java b/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
index 713fd4d..16dfb9b 100644
--- a/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
+++ b/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
@@ -18,5 +18,4 @@
public static final String LASTID_COOKIE = "gerrit.last_openid";
public static final String URL_LAUNCHPAD = "https://login.launchpad.net/+openid";
- public static final String URL_YAHOO = "https://me.yahoo.com";
}
diff --git a/java/com/google/gerrit/common/data/GlobalCapability.java b/java/com/google/gerrit/common/data/GlobalCapability.java
index 51d9ecd..8bfd960 100644
--- a/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -109,6 +109,9 @@
/** Can perform streaming of Gerrit events. */
public static final String STREAM_EVENTS = "streamEvents";
+ /** Can query permissions for any (project, user) pair */
+ public static final String VIEW_ACCESS = "viewAccess";
+
/** Can view all accounts, regardless of {@code accounts.visibility}. */
public static final String VIEW_ALL_ACCOUNTS = "viewAllAccounts";
@@ -124,9 +127,6 @@
/** Can view all pending tasks in the queue (not just the filtered set). */
public static final String VIEW_QUEUE = "viewQueue";
- /** Can query permissions for any (project, user) pair */
- public static final String VIEW_ACCESS = "viewAccess";
-
private static final List<String> NAMES_ALL;
private static final List<String> NAMES_LC;
private static final String[] RANGE_NAMES = {
@@ -152,12 +152,12 @@
NAMES_ALL.add(RUN_AS);
NAMES_ALL.add(RUN_GC);
NAMES_ALL.add(STREAM_EVENTS);
+ NAMES_ALL.add(VIEW_ACCESS);
NAMES_ALL.add(VIEW_ALL_ACCOUNTS);
NAMES_ALL.add(VIEW_CACHES);
NAMES_ALL.add(VIEW_CONNECTIONS);
NAMES_ALL.add(VIEW_PLUGINS);
NAMES_ALL.add(VIEW_QUEUE);
- NAMES_ALL.add(VIEW_ACCESS);
NAMES_LC = new ArrayList<>(NAMES_ALL.size());
for (String name : NAMES_ALL) {
diff --git a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
index f8c2ec5..781ed43 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
@@ -20,6 +20,7 @@
import com.google.gerrit.elasticsearch.bulk.IndexRequest;
import com.google.gerrit.elasticsearch.bulk.UpdateRequest;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.index.QueryOptions;
import com.google.gerrit.index.Schema;
@@ -28,7 +29,6 @@
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.IndexUtils;
import com.google.gerrit.server.index.group.GroupField;
import com.google.gerrit.server.index.group.GroupIndex;
diff --git a/java/com/google/gerrit/server/group/InternalGroup.java b/java/com/google/gerrit/entities/InternalGroup.java
similarity index 94%
rename from java/com/google/gerrit/server/group/InternalGroup.java
rename to java/com/google/gerrit/entities/InternalGroup.java
index f33adaf..ebfa36a 100644
--- a/java/com/google/gerrit/server/group/InternalGroup.java
+++ b/java/com/google/gerrit/entities/InternalGroup.java
@@ -12,13 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.group;
+package com.google.gerrit.entities;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.Account;
-import com.google.gerrit.entities.AccountGroup;
import java.io.Serializable;
import java.sql.Timestamp;
import org.eclipse.jgit.lib.ObjectId;
diff --git a/java/com/google/gerrit/entities/SubmitRecord.java b/java/com/google/gerrit/entities/SubmitRecord.java
index 67c6007..9ebc671 100644
--- a/java/com/google/gerrit/entities/SubmitRecord.java
+++ b/java/com/google/gerrit/entities/SubmitRecord.java
@@ -14,6 +14,9 @@
package com.google.gerrit.entities;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
+import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@@ -50,7 +53,11 @@
FORCED,
/**
- * An internal server error occurred preventing computation.
+ * A rule error caused by user misconfiguration.
+ *
+ * <p>This status should only be used to signal that the user has misconfigured the submit rule.
+ * In case plugins encounter server exceptions while evaluating the rule, they should throw a
+ * {@link RuntimeException} such as {@link IllegalStateException}.
*
* <p>Additional detail may be available in {@link SubmitRecord#errorMessage}.
*/
@@ -107,6 +114,17 @@
public Status status;
public Account.Id appliedBy;
+ /**
+ * Returns a new instance of {@link Label} that contains a new instance for each mutable field.
+ */
+ public Label deepCopy() {
+ Label copy = new Label();
+ copy.label = label;
+ copy.status = status;
+ copy.appliedBy = appliedBy;
+ return copy;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -134,6 +152,23 @@
}
}
+ /**
+ * Returns a new instance of {@link SubmitRecord} that contains a new instance for each mutable
+ * field.
+ */
+ public SubmitRecord deepCopy() {
+ SubmitRecord copy = new SubmitRecord();
+ copy.status = status;
+ copy.errorMessage = errorMessage;
+ if (labels != null) {
+ copy.labels = labels.stream().map(Label::deepCopy).collect(toImmutableList());
+ }
+ if (requirements != null) {
+ copy.requirements = ImmutableList.copyOf(requirements);
+ }
+ return copy;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index 6c15c0c..7cbfebd 100644
--- a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -21,6 +21,7 @@
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInfoDifference;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.CommitMessageInput;
@@ -32,6 +33,7 @@
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
import java.util.Arrays;
+import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@@ -260,6 +262,46 @@
EnumSet.complementOf(EnumSet.of(ListChangesOption.CHECK, ListChangesOption.SKIP_DIFFSTAT)));
}
+ default ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId, @Nullable String newMetaRevId) throws RestApiException {
+ return metaDiff(
+ oldMetaRevId,
+ newMetaRevId,
+ EnumSet.noneOf(ListChangesOption.class),
+ ImmutableListMultimap.of());
+ }
+
+ default ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId, @Nullable String newMetaRevId, ListChangesOption... options)
+ throws RestApiException {
+ return metaDiff(oldMetaRevId, newMetaRevId, Arrays.asList(options));
+ }
+
+ default ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId,
+ @Nullable String newMetaRevId,
+ Collection<ListChangesOption> options)
+ throws RestApiException {
+ return metaDiff(
+ oldMetaRevId,
+ newMetaRevId,
+ Sets.newEnumSet(options, ListChangesOption.class),
+ ImmutableListMultimap.of());
+ }
+
+ /**
+ * Gets the diff between a change's metadata with the two given refs.
+ *
+ * @param oldMetaRevId the SHA-1 of the 'before' metadata diffed against {@code newMetaRevId}
+ * @param newMetaRevId the SHA-1 of the 'after' metadata diffed against {@code oldMetaRevId}
+ */
+ ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId,
+ @Nullable String newMetaRevId,
+ EnumSet<ListChangesOption> options,
+ ImmutableListMultimap<String, String> pluginOptions)
+ throws RestApiException;
+
/** {@link #get(ListChangesOption...)} with no options included. */
default ChangeInfo info() throws RestApiException {
return get(EnumSet.noneOf(ListChangesOption.class));
@@ -370,7 +412,9 @@
* their patch set.
* @throws RestApiException
*/
- Map<String, List<CommentInfo>> drafts() throws RestApiException;
+ default Map<String, List<CommentInfo>> drafts() throws RestApiException {
+ return draftsRequest().get();
+ }
/**
* Get all draft comments for the current user on a change as a list.
@@ -379,7 +423,17 @@
* set.
* @throws RestApiException
*/
- List<CommentInfo> draftsAsList() throws RestApiException;
+ default List<CommentInfo> draftsAsList() throws RestApiException {
+ return draftsRequest().getAsList();
+ }
+
+ /**
+ * Get a {@link DraftsRequest} entity that can be used to retrieve draft comments.
+ *
+ * @return A {@link DraftsRequest} entity that can be used to retrieve the draft comments using
+ * {@link DraftsRequest#get()} or {@link DraftsRequest#getAsList()}.
+ */
+ DraftsRequest draftsRequest() throws RestApiException;
ChangeInfo check() throws RestApiException;
@@ -456,6 +510,8 @@
}
}
+ abstract class DraftsRequest extends CommentsRequest {}
+
abstract class SuggestedReviewersRequest {
private String query;
private int limit;
@@ -614,6 +670,16 @@
}
@Override
+ public ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId,
+ @Nullable String newMetaRevId,
+ EnumSet<ListChangesOption> options,
+ ImmutableListMultimap<String, String> pluginOptions)
+ throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public void setMessage(CommitMessageInput in) throws RestApiException {
throw new NotImplementedException();
}
@@ -696,6 +762,11 @@
}
@Override
+ public DraftsRequest draftsRequest() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public ChangeInfo check() throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfo.java b/java/com/google/gerrit/extensions/common/ChangeInfo.java
index b5f40ce..b771255 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -91,7 +91,7 @@
*/
public Boolean containsGitConflicts;
- public int _number;
+ public Integer _number;
public AccountInfo owner;
diff --git a/java/com/google/gerrit/extensions/common/FileInfo.java b/java/com/google/gerrit/extensions/common/FileInfo.java
index 510c2ad..c732663 100644
--- a/java/com/google/gerrit/extensions/common/FileInfo.java
+++ b/java/com/google/gerrit/extensions/common/FileInfo.java
@@ -44,4 +44,24 @@
public int hashCode() {
return Objects.hash(status, binary, oldPath, linesInserted, linesDeleted, sizeDelta, size);
}
+
+ @Override
+ public String toString() {
+ return "FileInfo{"
+ + "status="
+ + status
+ + ", binary="
+ + binary
+ + ", oldPath="
+ + oldPath
+ + ", linesInserted="
+ + linesInserted
+ + ", linesDeleted="
+ + linesDeleted
+ + ", sizeDelta="
+ + sizeDelta
+ + ", size="
+ + size
+ + "}";
+ }
}
diff --git a/java/com/google/gerrit/extensions/common/PluginConfigInfo.java b/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
index 13fc9ec..2d1d840 100644
--- a/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
+++ b/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
@@ -19,5 +19,4 @@
public class PluginConfigInfo {
public Boolean hasAvatars;
public List<String> jsResourcePaths;
- public List<String> htmlResourcePaths;
}
diff --git a/java/com/google/gerrit/httpd/BUILD b/java/com/google/gerrit/httpd/BUILD
index ee99702..cd3ebb9 100644
--- a/java/com/google/gerrit/httpd/BUILD
+++ b/java/com/google/gerrit/httpd/BUILD
@@ -32,7 +32,6 @@
"//lib:guava",
"//lib:jgit",
"//lib:jgit-servlet",
- "//lib:jsch",
"//lib:servlet-api",
"//lib:soy",
"//lib/auto:auto-value",
diff --git a/java/com/google/gerrit/httpd/RequestMetricsFilter.java b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
index c7a7540..c97b9ad 100644
--- a/java/com/google/gerrit/httpd/RequestMetricsFilter.java
+++ b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
@@ -14,6 +14,8 @@
package com.google.gerrit.httpd;
+import com.google.gerrit.metrics.proc.ThreadMXBeanFactory;
+import com.google.gerrit.metrics.proc.ThreadMXBeanInterface;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Singleton;
@@ -30,6 +32,8 @@
@Singleton
public class RequestMetricsFilter implements Filter {
+ public static final String METRICS_CONTEXT = "metrics-context";
+
public static Module module() {
return new ServletModule() {
@Override
@@ -39,6 +43,36 @@
};
}
+ public static class Context {
+ private static final ThreadMXBeanInterface threadMxBean = ThreadMXBeanFactory.create();
+ private final long startedTotalCpu;
+ private final long startedUserCpu;
+ private final long startedMemory;
+
+ Context() {
+ startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+ startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+ startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+ }
+
+ /** @return total CPU time in milliseconds for executing request */
+ public long getTotalCpuTime() {
+ return (threadMxBean.getCurrentThreadCpuTime() - startedTotalCpu) / 1_000_000;
+ }
+
+ /** @return CPU time in user mode in milliseconds for executing request */
+ public long getUserCpuTime() {
+ return (threadMxBean.getCurrentThreadUserTime() - startedUserCpu) / 1_000_000;
+ }
+
+ /** @return memory allocated in bytes for executing request */
+ public long getAllocatedMemory() {
+ return startedMemory == -1
+ ? -1
+ : threadMxBean.getCurrentThreadAllocatedBytes() - startedMemory;
+ }
+ }
+
private final RequestMetrics metrics;
@Inject
@@ -52,6 +86,7 @@
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
+ request.setAttribute(METRICS_CONTEXT, new Context());
Response rsp = new Response((HttpServletResponse) response, metrics);
chain.doFilter(request, rsp);
diff --git a/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index 283cd50..0b6008c 100644
--- a/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -59,9 +59,7 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final ImmutableMap<String, String> ALL_PROVIDERS =
- ImmutableMap.of(
- "launchpad", OpenIdUrls.URL_LAUNCHPAD,
- "yahoo", OpenIdUrls.URL_YAHOO);
+ ImmutableMap.of("launchpad", OpenIdUrls.URL_LAUNCHPAD);
private final ImmutableSet<String> suggestProviders;
private final Provider<String> urlProvider;
diff --git a/java/com/google/gerrit/httpd/init/BUILD b/java/com/google/gerrit/httpd/init/BUILD
index 37c63a2..adfbdcc 100644
--- a/java/com/google/gerrit/httpd/init/BUILD
+++ b/java/com/google/gerrit/httpd/init/BUILD
@@ -30,6 +30,7 @@
"//java/com/google/gerrit/sshd",
"//lib:guava",
"//lib:jgit",
+ "//lib:jgit-ssh-apache",
"//lib:servlet-api",
"//lib/flogger:api",
"//lib/guice",
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 2df4739..d03340b 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -103,6 +103,7 @@
import com.google.gerrit.sshd.SshHostKeyModule;
import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
+import com.google.gerrit.sshd.SshSessionFactoryInitializer;
import com.google.gerrit.sshd.commands.DefaultCommandModule;
import com.google.gerrit.sshd.commands.IndexCommandsModule;
import com.google.gerrit.sshd.commands.SequenceCommandsModule;
@@ -339,6 +340,7 @@
});
modules.add(new DefaultUrlFormatter.Module());
+ SshSessionFactoryInitializer.init(config);
modules.add(SshKeyCacheImpl.module());
modules.add(
new AbstractModule() {
diff --git a/java/com/google/gerrit/httpd/raw/SshInfoServlet.java b/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
index 1605360..ec67b8b 100644
--- a/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
+++ b/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
@@ -16,11 +16,11 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.gerrit.server.ssh.HostKey;
import com.google.gerrit.server.ssh.SshInfo;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.jcraft.jsch.HostKey;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@@ -59,14 +59,14 @@
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
- final List<HostKey> hostKeys = sshd.getHostKeys();
- final String out;
+ List<HostKey> hostKeys = sshd.getHostKeys();
+ String out;
if (!hostKeys.isEmpty()) {
String host = hostKeys.get(0).getHost();
String port = "22";
if (host.contains(":")) {
- final int p = host.lastIndexOf(':');
+ int p = host.lastIndexOf(':');
port = host.substring(p + 1);
host = host.substring(0, p);
}
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 6f3d5c6..9b86a4f 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -1581,9 +1581,11 @@
// Check if we want to delegate to a child collection. Child collections are bound with
// GET.name so we have to check for this since we haven't found any other views.
- core = views.get(PluginName.GERRIT, "GET." + p.get(0));
- if (core != null) {
- return new ViewData(PluginName.GERRIT, core);
+ if (method.equals("GET")) {
+ core = views.get(PluginName.GERRIT, "GET." + p.get(0));
+ if (core != null) {
+ return new ViewData(PluginName.GERRIT, core);
+ }
}
Map<String, RestView<RestResource>> r = new TreeMap<>();
diff --git a/java/com/google/gerrit/lucene/LuceneGroupIndex.java b/java/com/google/gerrit/lucene/LuceneGroupIndex.java
index 3d1d471..5cad588 100644
--- a/java/com/google/gerrit/lucene/LuceneGroupIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneGroupIndex.java
@@ -19,6 +19,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.index.FieldDef;
import com.google.gerrit.index.QueryOptions;
@@ -30,7 +31,6 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.IndexUtils;
import com.google.gerrit.server.index.group.GroupIndex;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/metrics/proc/ProcMetricModule.java b/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
index 20ac8fa..09e40c1 100644
--- a/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
+++ b/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
@@ -27,6 +27,7 @@
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
@@ -41,6 +42,7 @@
procCpuLoad(metrics);
procJvmGc(metrics);
procJvmMemory(metrics);
+ procJvmMemoryPool(metrics);
procJvmThread(metrics);
}
@@ -167,6 +169,50 @@
});
}
+ private void procJvmMemoryPool(MetricMaker metrics) {
+ Field<String> poolName =
+ Field.ofString("pool_name", Metadata.Builder::memoryPoolName)
+ .description("The name of the memory pool")
+ .build();
+
+ CallbackMetric1<String, Long> committed =
+ metrics.newCallbackMetric(
+ "proc/jvm/memory/pool/committed",
+ Long.class,
+ new Description("Committed pool size").setUnit(Units.BYTES),
+ poolName);
+
+ CallbackMetric1<String, Long> max =
+ metrics.newCallbackMetric(
+ "proc/jvm/memory/pool/max",
+ Long.class,
+ new Description("Max pool size").setUnit(Units.BYTES),
+ poolName);
+
+ CallbackMetric1<String, Long> used =
+ metrics.newCallbackMetric(
+ "proc/jvm/memory/pool/used",
+ Long.class,
+ new Description("Used pool size").setUnit(Units.BYTES),
+ poolName);
+
+ metrics.newTrigger(
+ committed,
+ max,
+ used,
+ () -> {
+ for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+ if (!pool.isValid()) {
+ continue;
+ }
+ MemoryUsage u = pool.getUsage();
+ committed.set(pool.getName(), u.getCommitted());
+ max.set(pool.getName(), u.getMax());
+ used.set(pool.getName(), u.getUsed());
+ }
+ });
+ }
+
private void procJvmGc(MetricMaker metrics) {
Field<String> gcNameField =
Field.ofString("gc_name", Metadata.Builder::garbageCollectorName)
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java
new file mode 100644
index 0000000..1e0c4f0
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+
+public class ThreadMXBeanFactory {
+
+ private ThreadMXBeanFactory() {}
+
+ public static ThreadMXBeanInterface create() {
+ ThreadMXBean sys = ManagementFactory.getThreadMXBean();
+ if (sys instanceof com.sun.management.ThreadMXBean) {
+ return new ThreadMXBeanSun(sys);
+ }
+ return new ThreadMXBeanJava(sys);
+ }
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java
new file mode 100644
index 0000000..546924f
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.gerrit.metrics.proc;
+
+public interface ThreadMXBeanInterface {
+ long getCurrentThreadCpuTime();
+
+ long getCurrentThreadUserTime();
+
+ long getCurrentThreadAllocatedBytes();
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java
new file mode 100644
index 0000000..29dd42a
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import java.lang.management.ThreadMXBean;
+
+class ThreadMXBeanJava implements ThreadMXBeanInterface {
+ private final ThreadMXBean sys;
+
+ ThreadMXBeanJava(ThreadMXBean sys) {
+ this.sys = sys;
+ }
+
+ @Override
+ public long getCurrentThreadCpuTime() {
+ return sys.getCurrentThreadCpuTime();
+ }
+
+ @Override
+ public long getCurrentThreadUserTime() {
+ return sys.getCurrentThreadUserTime();
+ }
+
+ @Override
+ public long getCurrentThreadAllocatedBytes() {
+ return -1;
+ }
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java
new file mode 100644
index 0000000..9e43a05
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import com.sun.management.ThreadMXBean;
+
+class ThreadMXBeanSun implements ThreadMXBeanInterface {
+ private final ThreadMXBean sys;
+
+ ThreadMXBeanSun(java.lang.management.ThreadMXBean sys) {
+ this.sys = (ThreadMXBean) sys;
+ }
+
+ @Override
+ public long getCurrentThreadCpuTime() {
+ return sys.getCurrentThreadCpuTime();
+ }
+
+ @Override
+ public long getCurrentThreadUserTime() {
+ return sys.getCurrentThreadUserTime();
+ }
+
+ @Override
+ public long getCurrentThreadAllocatedBytes() {
+ // TODO(ms): call getCurrentThreadAllocatedBytes as soon as this is available in the patched
+ // Java version used by bazel
+ return sys.getThreadAllocatedBytes(Thread.currentThread().getId());
+ }
+}
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index faedcb7..16eebf2 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -44,6 +44,7 @@
"//lib:args4j",
"//lib:guava",
"//lib:jgit",
+ "//lib:jgit-ssh-apache",
"//lib:protobuf",
"//lib:servlet-api-without-neverlink",
"//lib/auto:auto-value",
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 16c9d27..07bab24 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -114,6 +114,7 @@
import com.google.gerrit.sshd.SshHostKeyModule;
import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
+import com.google.gerrit.sshd.SshSessionFactoryInitializer;
import com.google.gerrit.sshd.commands.DefaultCommandModule;
import com.google.gerrit.sshd.commands.IndexCommandsModule;
import com.google.gerrit.sshd.commands.SequenceCommandsModule;
@@ -482,6 +483,7 @@
});
}
modules.add(new DefaultUrlFormatter.Module());
+ SshSessionFactoryInitializer.init(config);
if (sshd) {
modules.add(SshKeyCacheImpl.module());
} else {
diff --git a/java/com/google/gerrit/pgm/Reindex.java b/java/com/google/gerrit/pgm/Reindex.java
index c8d69f1c..3935268 100644
--- a/java/com/google/gerrit/pgm/Reindex.java
+++ b/java/com/google/gerrit/pgm/Reindex.java
@@ -29,10 +29,6 @@
import com.google.gerrit.lucene.LuceneIndexModule;
import com.google.gerrit.pgm.util.BatchProgramModule;
import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.server.LibModuleLoader;
-import com.google.gerrit.server.LibModuleType;
-import com.google.gerrit.server.ModuleOverloader;
-import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.index.IndexModule;
@@ -162,8 +158,7 @@
throw new IllegalStateException("unsupported index.type = " + indexType);
}
modules.add(indexModule);
- modules.add(new BatchProgramModule());
- modules.add(new H2CacheModule());
+ modules.add(new BatchProgramModule(dbInjector));
modules.add(
new FactoryModule() {
@Override
@@ -172,9 +167,7 @@
}
});
- return dbInjector.createChildInjector(
- ModuleOverloader.override(
- modules, LibModuleLoader.loadModules(dbInjector, LibModuleType.SYS_MODULE)));
+ return dbInjector.createChildInjector(modules);
}
private void overrideConfig() {
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
index 4e4c93b..2353116 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
@@ -16,6 +16,7 @@
import com.google.common.base.Strings;
import com.google.gerrit.httpd.GetUserFilter;
+import com.google.gerrit.httpd.RequestMetricsFilter;
import com.google.gerrit.httpd.restapi.LogRedactUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.util.SystemLog;
@@ -51,6 +52,9 @@
protected static final String P_LATENCY = "Latency";
protected static final String P_REFERER = "Referer";
protected static final String P_USER_AGENT = "User-Agent";
+ protected static final String P_CPU_TOTAL = "Cpu-Total";
+ protected static final String P_CPU_USER = "Cpu-User";
+ protected static final String P_MEMORY = "Memory";
private final AsyncAppender async;
@@ -114,6 +118,12 @@
set(event, P_REFERER, req.getHeader("Referer"));
set(event, P_USER_AGENT, req.getHeader("User-Agent"));
+ RequestMetricsFilter.Context ctx =
+ (RequestMetricsFilter.Context) req.getAttribute(RequestMetricsFilter.METRICS_CONTEXT);
+ set(event, P_CPU_TOTAL, ctx.getTotalCpuTime());
+ set(event, P_CPU_USER, ctx.getUserCpuTime());
+ set(event, P_MEMORY, ctx.getAllocatedMemory());
+
async.append(event);
}
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
index 95a5b07..5f4ec43 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
@@ -15,8 +15,11 @@
package com.google.gerrit.pgm.http.jetty;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CONTENT_LENGTH;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CPU_TOTAL;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CPU_USER;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_HOST;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_LATENCY;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_MEMORY;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_METHOD;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_PROTOCOL;
import static com.google.gerrit.pgm.http.jetty.HttpLog.P_REFERER;
@@ -48,6 +51,9 @@
public String status;
public String contentLength;
public String latency;
+ public String cpuTotal;
+ public String cpuUser;
+ public String memory;
public String referer;
public String userAgent;
@@ -62,6 +68,9 @@
this.status = getMdcString(event, P_STATUS);
this.contentLength = getMdcString(event, P_CONTENT_LENGTH);
this.latency = getMdcString(event, P_LATENCY);
+ this.cpuTotal = getMdcString(event, P_CPU_TOTAL);
+ this.cpuUser = getMdcString(event, P_CPU_USER);
+ this.memory = getMdcString(event, P_MEMORY);
this.referer = getMdcString(event, P_REFERER);
this.userAgent = getMdcString(event, P_USER_AGENT);
}
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
index 268f59f..e9e6866 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
@@ -71,6 +71,15 @@
buf.append(' ');
dq_opt(buf, event, HttpLog.P_USER_AGENT);
+ buf.append(' ');
+ opt(buf, event, HttpLog.P_CPU_TOTAL);
+
+ buf.append(' ');
+ opt(buf, event, HttpLog.P_CPU_USER);
+
+ buf.append(' ');
+ opt(buf, event, HttpLog.P_MEMORY);
+
buf.append('\n');
return buf.toString();
}
diff --git a/java/com/google/gerrit/pgm/init/GroupsOnInit.java b/java/com/google/gerrit/pgm/init/GroupsOnInit.java
index ca28255..95572b6 100644
--- a/java/com/google/gerrit/pgm/init/GroupsOnInit.java
+++ b/java/com/google/gerrit/pgm/init/GroupsOnInit.java
@@ -22,6 +22,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.pgm.init.api.AllUsersNameOnInitProvider;
import com.google.gerrit.pgm.init.api.InitFlags;
@@ -31,7 +32,6 @@
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.AuditLogFormatter;
import com.google.gerrit.server.group.db.GroupConfig;
import com.google.gerrit.server.group.db.GroupNameNotes;
diff --git a/java/com/google/gerrit/pgm/init/InitAdminUser.java b/java/com/google/gerrit/pgm/init/InitAdminUser.java
index effb4c6..ae640d0 100644
--- a/java/com/google/gerrit/pgm/init/InitAdminUser.java
+++ b/java/com/google/gerrit/pgm/init/InitAdminUser.java
@@ -19,6 +19,7 @@
import com.google.common.base.Strings;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.extensions.client.AuthType;
import com.google.gerrit.pgm.init.api.ConsoleUI;
@@ -28,7 +29,6 @@
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.account.AccountIndex;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.group.GroupIndex;
diff --git a/java/com/google/gerrit/pgm/util/BUILD b/java/com/google/gerrit/pgm/util/BUILD
index cfdd383..f7c2b75 100644
--- a/java/com/google/gerrit/pgm/util/BUILD
+++ b/java/com/google/gerrit/pgm/util/BUILD
@@ -12,6 +12,7 @@
"//java/com/google/gerrit/metrics",
"//java/com/google/gerrit/metrics/dropwizard",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/cache/mem",
"//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/schema",
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index 894757b..6c4454f 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -28,6 +28,9 @@
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.LibModuleLoader;
+import com.google.gerrit.server.LibModuleType;
+import com.google.gerrit.server.ModuleOverloader;
import com.google.gerrit.server.account.AccountCacheImpl;
import com.google.gerrit.server.account.AccountVisibilityProvider;
import com.google.gerrit.server.account.CapabilityCollection;
@@ -38,6 +41,7 @@
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
import com.google.gerrit.server.cache.CacheRemovalListener;
+import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.change.ChangeKindCacheImpl;
@@ -82,22 +86,33 @@
import com.google.gerrit.server.rules.PrologModule;
import com.google.gerrit.server.rules.SubmitRule;
import com.google.gerrit.server.update.BatchUpdate;
+import com.google.inject.Injector;
+import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Providers;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/** Module for programs that perform batch operations on a site. */
public class BatchProgramModule extends FactoryModule {
+ private Injector parentInjector;
+
+ public BatchProgramModule(Injector parentInjector) {
+ this.parentInjector = parentInjector;
+ }
+
@SuppressWarnings("rawtypes")
@Override
protected void configure() {
- install(new DiffExecutorModule());
- install(new SysExecutorModule());
- install(BatchUpdate.module());
- install(PatchListCacheImpl.module());
- install(new DefaultUrlFormatter.Module());
+ List<Module> modules = new ArrayList<>();
+
+ modules.add(new DiffExecutorModule());
+ modules.add(new SysExecutorModule());
+ modules.add(BatchUpdate.module());
+ modules.add(PatchListCacheImpl.module());
+ modules.add(new DefaultUrlFormatter.Module());
// There is the concept of LifecycleModule, in Gerrit's own extension to Guice, which has these:
// listener().to(SomeClassImplementingLifecycleListener.class);
@@ -106,7 +121,7 @@
// plugins get loaded and the respective Guice modules installed so that the on-line reindexing
// will happen with the proper classes (e.g. group backends, custom Prolog predicates) and the
// associated rules ready to be evaluated.
- install(new PluginModule());
+ modules.add(new PluginModule());
// We're just running through each change
// once, so don't worry about cache removal.
@@ -146,24 +161,24 @@
.annotatedWith(GitReceivePackGroups.class)
.toInstance(Collections.emptySet());
- install(new BatchGitModule());
- install(new DefaultPermissionBackendModule());
- install(new DefaultMemoryCacheModule());
-
- install(new ExternalIdModule());
- install(new GroupModule());
- install(new NoteDbModule());
- install(AccountCacheImpl.module());
- install(DefaultPreferencesCacheImpl.module());
- install(GroupCacheImpl.module());
- install(GroupIncludeCacheImpl.module());
- install(ProjectCacheImpl.module());
- install(SectionSortCache.module());
- install(ChangeKindCacheImpl.module());
- install(MergeabilityCacheImpl.module());
- install(ServiceUserClassifierImpl.module());
- install(TagCache.module());
- install(PureRevertCache.module());
+ modules.add(new BatchGitModule());
+ modules.add(new DefaultPermissionBackendModule());
+ modules.add(new DefaultMemoryCacheModule());
+ modules.add(new H2CacheModule());
+ modules.add(new ExternalIdModule());
+ modules.add(new GroupModule());
+ modules.add(new NoteDbModule());
+ modules.add(AccountCacheImpl.module());
+ modules.add(DefaultPreferencesCacheImpl.module());
+ modules.add(GroupCacheImpl.module());
+ modules.add(GroupIncludeCacheImpl.module());
+ modules.add(ProjectCacheImpl.module());
+ modules.add(SectionSortCache.module());
+ modules.add(ChangeKindCacheImpl.module());
+ modules.add(MergeabilityCacheImpl.module());
+ modules.add(ServiceUserClassifierImpl.module());
+ modules.add(TagCache.module());
+ modules.add(PureRevertCache.module());
factory(CapabilityCollection.Factory.class);
factory(ChangeData.AssistedFactory.class);
factory(ChangeIsVisibleToPredicate.Factory.class);
@@ -172,9 +187,9 @@
// Submit rules
DynamicSet.setOf(binder(), SubmitRule.class);
factory(SubmitRuleEvaluator.Factory.class);
- install(new PrologModule());
- install(new DefaultSubmitRule.Module());
- install(new IgnoreSelfApprovalRule.Module());
+ modules.add(new PrologModule());
+ modules.add(new DefaultSubmitRule.Module());
+ modules.add(new IgnoreSelfApprovalRule.Module());
bind(ChangeJson.Factory.class).toProvider(Providers.of(null));
bind(EventUtil.class).toProvider(Providers.of(null));
@@ -182,5 +197,10 @@
bind(RevisionCreated.class).toInstance(RevisionCreated.DISABLED);
bind(WorkInProgressStateChanged.class).toInstance(WorkInProgressStateChanged.DISABLED);
bind(AccountVisibility.class).toProvider(AccountVisibilityProvider.class).in(SINGLETON);
+
+ ModuleOverloader.override(
+ modules, LibModuleLoader.loadModules(parentInjector, LibModuleType.SYS_BATCH_MODULE))
+ .stream()
+ .forEach(this::install);
}
}
diff --git a/java/com/google/gerrit/server/BUILD b/java/com/google/gerrit/server/BUILD
index 9fa7456..404906d 100644
--- a/java/com/google/gerrit/server/BUILD
+++ b/java/com/google/gerrit/server/BUILD
@@ -97,7 +97,6 @@
"//lib:guava-retrying",
"//lib:jgit",
"//lib:jgit-archive",
- "//lib:jsch",
"//lib:juniversalchardet",
"//lib:mime-util",
"//lib:protobuf",
diff --git a/java/com/google/gerrit/server/LibModuleType.java b/java/com/google/gerrit/server/LibModuleType.java
index 557f8c0..b9cb196 100644
--- a/java/com/google/gerrit/server/LibModuleType.java
+++ b/java/com/google/gerrit/server/LibModuleType.java
@@ -20,6 +20,9 @@
/** Module for the sysInjector. */
SYS_MODULE("Module"),
+ /** BatchModule for the sysInjector */
+ SYS_BATCH_MODULE("BatchModule"),
+
/** Module for the dbInjector. */
DB_MODULE("DbModule");
diff --git a/java/com/google/gerrit/server/PublishCommentsOp.java b/java/com/google/gerrit/server/PublishCommentsOp.java
index 358ce92..a2ce6fa 100644
--- a/java/com/google/gerrit/server/PublishCommentsOp.java
+++ b/java/com/google/gerrit/server/PublishCommentsOp.java
@@ -31,7 +31,7 @@
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.CommentsRejectedException;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoView;
import com.google.gerrit.server.util.LabelVote;
import com.google.inject.Inject;
@@ -108,7 +108,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (message == null || comments.isEmpty()) {
return;
}
@@ -128,7 +128,7 @@
.sendAsync();
}
commentAdded.fire(
- changeNotes.getChange(),
+ ctx.getChangeData(changeNotes),
ps,
ctx.getAccount(),
message.getMessage(),
diff --git a/java/com/google/gerrit/server/account/GroupCache.java b/java/com/google/gerrit/server/account/GroupCache.java
index 90d3aa9..aaae95a 100644
--- a/java/com/google/gerrit/server/account/GroupCache.java
+++ b/java/com/google/gerrit/server/account/GroupCache.java
@@ -15,7 +15,9 @@
package com.google.gerrit.server.account;
import com.google.gerrit.entities.AccountGroup;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.entities.InternalGroup;
+import java.util.Collection;
+import java.util.Map;
import java.util.Optional;
/** Tracks group objects in memory for efficient access. */
@@ -48,6 +50,18 @@
Optional<InternalGroup> get(AccountGroup.UUID groupUuid);
/**
+ * Returns a {@code Map} of {@code AccountGroup.UUID} to {@code InternalGroup} for the given
+ * groups UUIDs. If not cached yet the groups are loaded. If a group can't be loaded (e.g. because
+ * it is missing), the entry will be missing from the result.
+ *
+ * @param groupUuids UUIDs of the groups that should be retrieved
+ * @return {@code Map} of {@code AccountGroup.UUID} to {@code InternalGroup} instances for the
+ * given group UUIDs, if a group can't be loaded (e.g. because it is missing), the entry will
+ * be missing from the result.
+ */
+ Map<AccountGroup.UUID, InternalGroup> get(Collection<AccountGroup.UUID> groupUuids);
+
+ /**
* Removes the association of the given ID with a group.
*
* <p>The next call to {@link #get(AccountGroup.Id)} won't provide a cached value.
@@ -88,4 +102,7 @@
* @param groupUuid the UUID of a possibly associated group
*/
void evict(AccountGroup.UUID groupUuid);
+
+ /** @see #evict(AccountGroup.UUID); */
+ void evict(Collection<AccountGroup.UUID> groupUuid);
}
diff --git a/java/com/google/gerrit/server/account/GroupCacheImpl.java b/java/com/google/gerrit/server/account/GroupCacheImpl.java
index fe22028..eaec9ba 100644
--- a/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -14,12 +14,27 @@
package com.google.gerrit.server.account;
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
+
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
+import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.proto.Protos;
import com.google.gerrit.server.cache.CacheModule;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.cache.proto.Cache;
+import com.google.gerrit.server.cache.serialize.CacheSerializer;
+import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
+import com.google.gerrit.server.cache.serialize.ProtobufSerializer;
+import com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
@@ -31,8 +46,19 @@
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
+import org.bouncycastle.util.Strings;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
/** Tracks group objects in memory for efficient access. */
@Singleton
@@ -42,6 +68,7 @@
private static final String BYID_NAME = "groups";
private static final String BYNAME_NAME = "groups_byname";
private static final String BYUUID_NAME = "groups_byuuid";
+ private static final String BYUUID_NAME_PERSISTED = "groups_byuuid_persisted";
public static Module module() {
return new CacheModule() {
@@ -55,9 +82,35 @@
.maximumWeight(Long.MAX_VALUE)
.loader(ByNameLoader.class);
+ // We split the group cache into two parts for performance reasons:
+ // 1) An in-memory part that has only the group ref uuid as key.
+ // 2) A persisted part that has the group ref uuid and sha1 of the ref as key.
+ //
+ // When loading dashboards or returning change query results we potentially
+ // need to access many groups.
+ // We want the persisted cache to be immutable and we want it to be impossible that a
+ // value for a given key is out of date. We therefore require the sha-1 in the key. That
+ // is in line with the rest of the caches in Gerrit.
+ //
+ // Splitting the cache into two chunks internally in this class allows us to retain
+ // the existing performance guarantees of not requiring reads for the repo for values
+ // cached in-memory but also to persist the cache which leads to a much improved
+ // cold-start behavior and in-memory miss latency.
+
cache(BYUUID_NAME, String.class, new TypeLiteral<Optional<InternalGroup>>() {})
.maximumWeight(Long.MAX_VALUE)
- .loader(ByUUIDLoader.class);
+ .loader(ByUUIDInMemoryLoader.class);
+
+ persist(
+ BYUUID_NAME_PERSISTED,
+ Cache.GroupKeyProto.class,
+ new TypeLiteral<InternalGroup>() {})
+ .loader(PersistedByUUIDLoader.class)
+ .keySerializer(new ProtobufSerializer<>(Cache.GroupKeyProto.parser()))
+ .valueSerializer(PersistedInternalGroupSerializer.INSTANCE)
+ .diskLimit(1 << 30) // 1 GiB
+ .version(1)
+ .maximumWeight(0);
bind(GroupCacheImpl.class);
bind(GroupCache.class).to(GroupCacheImpl.class);
@@ -117,6 +170,20 @@
}
@Override
+ public Map<AccountGroup.UUID, InternalGroup> get(Collection<AccountGroup.UUID> groupUuids) {
+ try {
+ Set<String> groupUuidsStringSet =
+ groupUuids.stream().map(u -> u.get()).collect(toImmutableSet());
+ return byUUID.getAll(groupUuidsStringSet).entrySet().stream()
+ .filter(g -> g.getValue().isPresent())
+ .collect(toImmutableMap(g -> AccountGroup.uuid(g.getKey()), g -> g.getValue().get()));
+ } catch (ExecutionException e) {
+ logger.atWarning().withCause(e).log("Cannot look up groups %s by uuids", groupUuids);
+ return ImmutableMap.of();
+ }
+ }
+
+ @Override
public void evict(AccountGroup.Id groupId) {
if (groupId != null) {
logger.atFine().log("Evict group %s by ID", groupId.get());
@@ -140,6 +207,14 @@
}
}
+ @Override
+ public void evict(Collection<AccountGroup.UUID> groupUuids) {
+ if (groupUuids != null && !groupUuids.isEmpty()) {
+ logger.atFine().log("Evict groups %s by UUID", groupUuids);
+ byUUID.invalidateAll(groupUuids);
+ }
+ }
+
static class ByIdLoader extends CacheLoader<AccountGroup.Id, Optional<InternalGroup>> {
private final Provider<InternalGroupQuery> groupQueryProvider;
@@ -150,7 +225,7 @@
@Override
public Optional<InternalGroup> load(AccountGroup.Id key) throws Exception {
- try (TraceTimer timer =
+ try (TraceTimer ignored =
TraceContext.newTimer(
"Loading group by ID", Metadata.builder().groupId(key.get()).build())) {
return groupQueryProvider.get().byId(key);
@@ -168,7 +243,7 @@
@Override
public Optional<InternalGroup> load(String name) throws Exception {
- try (TraceTimer timer =
+ try (TraceTimer ignored =
TraceContext.newTimer(
"Loading group by name", Metadata.builder().groupName(name).build())) {
return groupQueryProvider.get().byName(AccountGroup.nameKey(name));
@@ -176,21 +251,108 @@
}
}
- static class ByUUIDLoader extends CacheLoader<String, Optional<InternalGroup>> {
- private final Groups groups;
+ static class ByUUIDInMemoryLoader extends CacheLoader<String, Optional<InternalGroup>> {
+ private final LoadingCache<Cache.GroupKeyProto, InternalGroup> persistedCache;
+ private final GitRepositoryManager repoManager;
+ private final AllUsersName allUsersName;
@Inject
- ByUUIDLoader(Groups groups) {
- this.groups = groups;
+ ByUUIDInMemoryLoader(
+ @Named(BYUUID_NAME_PERSISTED)
+ LoadingCache<Cache.GroupKeyProto, InternalGroup> persistedCache,
+ GitRepositoryManager repoManager,
+ AllUsersName allUsersName) {
+ this.persistedCache = persistedCache;
+ this.repoManager = repoManager;
+ this.allUsersName = allUsersName;
}
@Override
public Optional<InternalGroup> load(String uuid) throws Exception {
- try (TraceTimer timer =
- TraceContext.newTimer(
- "Loading group by UUID", Metadata.builder().groupUuid(uuid).build())) {
- return groups.getGroup(AccountGroup.uuid(uuid));
+ return loadAll(ImmutableSet.of(uuid)).get(uuid);
+ }
+
+ @Override
+ public Map<String, Optional<InternalGroup>> loadAll(Iterable<? extends String> uuids)
+ throws Exception {
+ Map<String, Optional<InternalGroup>> toReturn = new HashMap<>();
+ if (Iterables.isEmpty(uuids)) {
+ return toReturn;
}
+ Iterator<? extends String> uuidIterator = uuids.iterator();
+ List<Cache.GroupKeyProto> keyList = new ArrayList<>();
+ try (TraceTimer ignored =
+ TraceContext.newTimer(
+ "Loading group from serialized cache",
+ Metadata.builder().cacheName(BYUUID_NAME_PERSISTED).build());
+ Repository allUsers = repoManager.openRepository(allUsersName)) {
+ while (uuidIterator.hasNext()) {
+ String currentUuid = uuidIterator.next();
+ String ref = RefNames.refsGroups(AccountGroup.uuid(currentUuid));
+ Ref sha1 = allUsers.exactRef(ref);
+ if (sha1 == null) {
+ toReturn.put(currentUuid, Optional.empty());
+ continue;
+ }
+ Cache.GroupKeyProto key =
+ Cache.GroupKeyProto.newBuilder()
+ .setUuid(currentUuid)
+ .setRevision(ObjectIdConverter.create().toByteString(sha1.getObjectId()))
+ .build();
+ keyList.add(key);
+ }
+ }
+ persistedCache.getAll(keyList).entrySet().stream()
+ .forEach(g -> toReturn.put(g.getKey().getUuid(), Optional.of(g.getValue())));
+ return toReturn;
+ }
+ }
+
+ static class PersistedByUUIDLoader extends CacheLoader<Cache.GroupKeyProto, InternalGroup> {
+ private final Groups groups;
+
+ @Inject
+ PersistedByUUIDLoader(Groups groups) {
+ this.groups = groups;
+ }
+
+ @Override
+ public InternalGroup load(Cache.GroupKeyProto key) throws Exception {
+ try (TraceTimer ignored =
+ TraceContext.newTimer(
+ "Loading group by UUID", Metadata.builder().groupUuid(key.getUuid()).build())) {
+ ObjectId sha1 = ObjectIdConverter.create().fromByteString(key.getRevision());
+ Optional<InternalGroup> loadedGroup =
+ groups.getGroup(AccountGroup.uuid(key.getUuid()), sha1);
+ if (!loadedGroup.isPresent()) {
+ throw new IllegalStateException(
+ String.format(
+ "group %s should have the sha-1 %s, but " + "it was not found",
+ key.getUuid(), sha1.getName()));
+ }
+ return loadedGroup.get();
+ }
+ }
+ }
+
+ private enum PersistedInternalGroupSerializer implements CacheSerializer<InternalGroup> {
+ INSTANCE;
+
+ @Override
+ public byte[] serialize(InternalGroup value) {
+ if (value == null) {
+ return new byte[0];
+ }
+ return Protos.toByteArray(InternalGroupSerializer.serialize(value));
+ }
+
+ @Override
+ public InternalGroup deserialize(byte[] in) {
+ if (Strings.fromByteArray(in).isEmpty()) {
+ return null;
+ }
+ return InternalGroupSerializer.deserialize(
+ Protos.parseUnchecked(Cache.InternalGroupProto.parser(), in));
}
}
}
diff --git a/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java b/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
index 073ff84..f203240 100644
--- a/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
+++ b/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
@@ -25,13 +25,13 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.proto.Protos;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.proto.Cache.AllExternalGroupsProto;
import com.google.gerrit.server.cache.proto.Cache.AllExternalGroupsProto.ExternalGroupProto;
import com.google.gerrit.server.cache.serialize.CacheSerializer;
import com.google.gerrit.server.cache.serialize.StringCacheSerializer;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
diff --git a/java/com/google/gerrit/server/account/GroupMembers.java b/java/com/google/gerrit/server/account/GroupMembers.java
index c03ffd0..3ed82a1 100644
--- a/java/com/google/gerrit/server/account/GroupMembers.java
+++ b/java/com/google/gerrit/server/account/GroupMembers.java
@@ -22,8 +22,8 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.NoSuchProjectException;
diff --git a/java/com/google/gerrit/server/account/IncludingGroupMembership.java b/java/com/google/gerrit/server/account/IncludingGroupMembership.java
index 9cb11a6..8cec8bf 100644
--- a/java/com/google/gerrit/server/account/IncludingGroupMembership.java
+++ b/java/com/google/gerrit/server/account/IncludingGroupMembership.java
@@ -19,15 +19,14 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -83,6 +82,9 @@
}
if (tryExpanding) {
+ Set<AccountGroup.UUID> queryIdsSet = new HashSet<>();
+ queryIds.forEach(i -> queryIdsSet.add(i));
+ Map<AccountGroup.UUID, InternalGroup> groups = groupCache.get(queryIdsSet);
for (AccountGroup.UUID id : queryIds) {
if (memberOf.containsKey(id)) {
// Membership was earlier proven to be false.
@@ -90,15 +92,15 @@
}
memberOf.put(id, false);
- Optional<InternalGroup> group = groupCache.get(id);
- if (!group.isPresent()) {
+ InternalGroup group = groups.get(id);
+ if (group == null) {
continue;
}
- if (user.isIdentifiedUser() && group.get().getMembers().contains(user.getAccountId())) {
+ if (user.isIdentifiedUser() && group.getMembers().contains(user.getAccountId())) {
memberOf.put(id, true);
return true;
}
- if (search(group.get().getSubgroups())) {
+ if (search(group.getSubgroups())) {
memberOf.put(id, true);
return true;
}
diff --git a/java/com/google/gerrit/server/account/InternalGroupBackend.java b/java/com/google/gerrit/server/account/InternalGroupBackend.java
index 8761081..91fe701 100644
--- a/java/com/google/gerrit/server/account/InternalGroupBackend.java
+++ b/java/com/google/gerrit/server/account/InternalGroupBackend.java
@@ -20,8 +20,8 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.group.db.GroupsNoteDbConsistencyChecker;
diff --git a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
index 3ee2c54..27ac9f4 100644
--- a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
+++ b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
@@ -17,8 +17,8 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Scopes;
diff --git a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 8047e0e..0b340b8 100644
--- a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -46,6 +46,7 @@
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInfoDifference;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.CommitMessageInput;
@@ -80,6 +81,7 @@
import com.google.gerrit.server.restapi.change.GetAssignee;
import com.google.gerrit.server.restapi.change.GetChange;
import com.google.gerrit.server.restapi.change.GetHashtags;
+import com.google.gerrit.server.restapi.change.GetMetaDiff;
import com.google.gerrit.server.restapi.change.GetPastAssignees;
import com.google.gerrit.server.restapi.change.GetPureRevert;
import com.google.gerrit.server.restapi.change.GetTopic;
@@ -149,6 +151,7 @@
private final ChangeIncludedIn includedIn;
private final PostReviewers postReviewers;
private final Provider<GetChange> getChangeProvider;
+ private final Provider<GetMetaDiff> getMetaDiffProvider;
private final PostHashtags postHashtags;
private final GetHashtags getHashtags;
private final AttentionSet attentionSet;
@@ -160,7 +163,7 @@
private final DeleteAssignee deleteAssignee;
private final Provider<ListChangeComments> listCommentsProvider;
private final ListChangeRobotComments listChangeRobotComments;
- private final ListChangeDrafts listDrafts;
+ private final Provider<ListChangeDrafts> listDraftsProvider;
private final ChangeEditApiImpl.Factory changeEditApi;
private final Check check;
private final Index index;
@@ -204,6 +207,7 @@
ChangeIncludedIn includedIn,
PostReviewers postReviewers,
Provider<GetChange> getChangeProvider,
+ Provider<GetMetaDiff> getMetaDiffProvider,
PostHashtags postHashtags,
GetHashtags getHashtags,
AttentionSet attentionSet,
@@ -215,7 +219,7 @@
DeleteAssignee deleteAssignee,
Provider<ListChangeComments> listCommentsProvider,
ListChangeRobotComments listChangeRobotComments,
- ListChangeDrafts listDrafts,
+ Provider<ListChangeDrafts> listDraftsProvider,
ChangeEditApiImpl.Factory changeEditApi,
Check check,
Index index,
@@ -257,6 +261,7 @@
this.includedIn = includedIn;
this.postReviewers = postReviewers;
this.getChangeProvider = getChangeProvider;
+ this.getMetaDiffProvider = getMetaDiffProvider;
this.postHashtags = postHashtags;
this.getHashtags = getHashtags;
this.attentionSet = attentionSet;
@@ -268,7 +273,7 @@
this.deleteAssignee = deleteAssignee;
this.listCommentsProvider = listCommentsProvider;
this.listChangeRobotComments = listChangeRobotComments;
- this.listDrafts = listDrafts;
+ this.listDraftsProvider = listDraftsProvider;
this.changeEditApi = changeEditApi;
this.check = check;
this.index = index;
@@ -517,6 +522,25 @@
}
@Override
+ public ChangeInfoDifference metaDiff(
+ @Nullable String oldMetaRevId,
+ @Nullable String newMetaRevId,
+ EnumSet<ListChangesOption> options,
+ ImmutableListMultimap<String, String> pluginOptions)
+ throws RestApiException {
+ try (DynamicOptions dynamicOptions = new DynamicOptions(injector, dynamicBeans)) {
+ GetMetaDiff metaDiff = getMetaDiffProvider.get();
+ metaDiff.setOldMetaRevId(oldMetaRevId);
+ metaDiff.setNewMetaRevId(newMetaRevId);
+ options.forEach(metaDiff::addOption);
+ dynamicOptionParser.parseDynamicOptions(metaDiff, pluginOptions, dynamicOptions);
+ return metaDiff.apply(change).value();
+ } catch (Exception e) {
+ throw asRestApiException("Cannot retrieve metaDiff", e);
+ }
+ }
+
+ @Override
public ChangeEditApi edit() throws RestApiException {
return changeEditApi.create(change);
}
@@ -605,7 +629,7 @@
}
@Override
- public CommentsRequest commentsRequest() throws RestApiException {
+ public CommentsRequest commentsRequest() {
return new CommentsRequest() {
@Override
public Map<String, List<CommentInfo>> get() throws RestApiException {
@@ -643,21 +667,32 @@
}
@Override
- public Map<String, List<CommentInfo>> drafts() throws RestApiException {
- try {
- return listDrafts.apply(change).value();
- } catch (Exception e) {
- throw asRestApiException("Cannot get drafts", e);
- }
- }
+ public DraftsRequest draftsRequest() {
+ return new DraftsRequest() {
+ @Override
+ public Map<String, List<CommentInfo>> get() throws RestApiException {
+ try {
+ ListChangeDrafts listDrafts = listDraftsProvider.get();
+ listDrafts.setContext(this.getContext());
+ listDrafts.setContextPadding(this.getContextPadding());
+ return listDrafts.apply(change).value();
+ } catch (Exception e) {
+ throw asRestApiException("Cannot get drafts", e);
+ }
+ }
- @Override
- public List<CommentInfo> draftsAsList() throws RestApiException {
- try {
- return listDrafts.getComments(change);
- } catch (Exception e) {
- throw asRestApiException("Cannot get drafts", e);
- }
+ @Override
+ public List<CommentInfo> getAsList() throws RestApiException {
+ try {
+ ListChangeDrafts listDrafts = listDraftsProvider.get();
+ listDrafts.setContext(this.getContext());
+ listDrafts.setContextPadding(this.getContextPadding());
+ return listDrafts.getComments(change);
+ } catch (Exception e) {
+ throw asRestApiException("Cannot get drafts", e);
+ }
+ }
+ };
}
@Override
diff --git a/java/com/google/gerrit/server/args4j/AccountGroupIdHandler.java b/java/com/google/gerrit/server/args4j/AccountGroupIdHandler.java
index 66d0224..0cedf19 100644
--- a/java/com/google/gerrit/server/args4j/AccountGroupIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/AccountGroupIdHandler.java
@@ -17,8 +17,8 @@
import static com.google.gerrit.util.cli.Localizable.localizable;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.Optional;
diff --git a/java/com/google/gerrit/server/args4j/AccountGroupUUIDHandler.java b/java/com/google/gerrit/server/args4j/AccountGroupUUIDHandler.java
index e88f6df..d3ed3e4 100644
--- a/java/com/google/gerrit/server/args4j/AccountGroupUUIDHandler.java
+++ b/java/com/google/gerrit/server/args4j/AccountGroupUUIDHandler.java
@@ -19,10 +19,10 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
diff --git a/java/com/google/gerrit/server/audit/BUILD b/java/com/google/gerrit/server/audit/BUILD
index 0870786..3faa259 100644
--- a/java/com/google/gerrit/server/audit/BUILD
+++ b/java/com/google/gerrit/server/audit/BUILD
@@ -46,7 +46,6 @@
"//lib:guava-retrying",
"//lib:jgit",
"//lib:jgit-archive",
- "//lib:jsch",
"//lib:juniversalchardet",
"//lib:mime-util",
"//lib:protobuf",
diff --git a/java/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializer.java b/java/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializer.java
new file mode 100644
index 0000000..7449917
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializer.java
@@ -0,0 +1,82 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache.serialize.entities;
+
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
+
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
+import com.google.gerrit.server.cache.proto.Cache;
+import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
+import java.sql.Timestamp;
+
+/** Helper to (de)serialize values for caches. */
+public class InternalGroupSerializer {
+ public static InternalGroup deserialize(Cache.InternalGroupProto proto) {
+ InternalGroup.Builder builder =
+ InternalGroup.builder()
+ .setId(AccountGroup.id(proto.getId()))
+ .setNameKey(AccountGroup.nameKey(proto.getName()))
+ .setOwnerGroupUUID(AccountGroup.uuid(proto.getOwnerGroupUuid()))
+ .setVisibleToAll(proto.getIsVisibleToAll())
+ .setGroupUUID(AccountGroup.uuid(proto.getGroupUuid()))
+ .setCreatedOn(new Timestamp(proto.getCreatedOn()))
+ .setMembers(
+ proto.getMembersIdsList().stream()
+ .map(a -> Account.id(a))
+ .collect(toImmutableSet()))
+ .setSubgroups(
+ proto.getSubgroupUuidsList().stream()
+ .map(s -> AccountGroup.uuid(s))
+ .collect(toImmutableSet()));
+
+ if (!proto.getDescription().isEmpty()) {
+ builder.setDescription(proto.getDescription());
+ }
+
+ if (!proto.getRefState().isEmpty()) {
+ builder.setRefState(ObjectIdConverter.create().fromByteString(proto.getRefState()));
+ }
+
+ return builder.build();
+ }
+
+ public static Cache.InternalGroupProto serialize(InternalGroup autoValue) {
+ Cache.InternalGroupProto.Builder builder =
+ Cache.InternalGroupProto.newBuilder()
+ .setId(autoValue.getId().get())
+ .setName(autoValue.getName())
+ .setOwnerGroupUuid(autoValue.getOwnerGroupUUID().get())
+ .setIsVisibleToAll(autoValue.isVisibleToAll())
+ .setGroupUuid(autoValue.getGroupUUID().get())
+ .setCreatedOn(autoValue.getCreatedOn().getTime());
+
+ autoValue.getMembers().stream().forEach(m -> builder.addMembersIds(m.get()));
+ autoValue.getSubgroups().stream().forEach(s -> builder.addSubgroupUuids(s.get()));
+
+ if (autoValue.getDescription() != null) {
+ builder.setDescription(autoValue.getDescription());
+ }
+
+ if (autoValue.getRefState() != null) {
+ builder.setRefState(ObjectIdConverter.create().toByteString(autoValue.getRefState()));
+ }
+
+ return builder.build();
+ }
+
+ private InternalGroupSerializer() {}
+}
diff --git a/java/com/google/gerrit/server/change/AbandonOp.java b/java/com/google/gerrit/server/change/AbandonOp.java
index 6c39ed0..f88e6a9 100644
--- a/java/com/google/gerrit/server/change/AbandonOp.java
+++ b/java/com/google/gerrit/server/change/AbandonOp.java
@@ -32,7 +32,7 @@
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -111,7 +111,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
NotifyResolver.Result notify = ctx.getNotify(change.getId());
try {
ReplyToChangeSender emailSender =
@@ -127,6 +127,12 @@
} catch (Exception e) {
logger.atSevere().withCause(e).log("Cannot email update for change %s", change.getId());
}
- changeAbandoned.fire(change, patchSet, accountState, msgTxt, ctx.getWhen(), notify.handling());
+ changeAbandoned.fire(
+ ctx.getChangeData(change),
+ patchSet,
+ accountState,
+ msgTxt,
+ ctx.getWhen(),
+ notify.handling());
}
}
diff --git a/java/com/google/gerrit/server/change/ActionJson.java b/java/com/google/gerrit/server/change/ActionJson.java
index 6f28dad..54ebf40 100644
--- a/java/com/google/gerrit/server/change/ActionJson.java
+++ b/java/com/google/gerrit/server/change/ActionJson.java
@@ -31,7 +31,7 @@
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.extensions.webui.UiActions;
-import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -89,9 +89,9 @@
return Lists.newArrayList(visitorSet);
}
- void addChangeActions(ChangeInfo to, ChangeNotes notes) {
+ void addChangeActions(ChangeInfo to, ChangeData changeData) {
List<ActionVisitor> visitors = visitors();
- to.actions = toActionMap(notes, visitors, copy(visitors, to));
+ to.actions = toActionMap(changeData, visitors, copy(visitors, to));
}
void addRevisionActions(@Nullable ChangeInfo changeInfo, RevisionInfo to, RevisionResource rsrc) {
@@ -167,7 +167,7 @@
}
private Map<String, ActionInfo> toActionMap(
- ChangeNotes notes, List<ActionVisitor> visitors, ChangeInfo changeInfo) {
+ ChangeData changeData, List<ActionVisitor> visitors, ChangeInfo changeInfo) {
CurrentUser user = userProvider.get();
Map<String, ActionInfo> out = new LinkedHashMap<>();
if (!user.isIdentifiedUser()) {
@@ -175,12 +175,12 @@
}
Iterable<UiAction.Description> descs =
- uiActions.from(changeViews, changeResourceFactory.create(notes, user));
+ uiActions.from(changeViews, changeResourceFactory.create(changeData, user));
// The followup action is a client-side only operation that does not
// have a server side handler. It must be manually registered into the
// resulting action map.
- if (!notes.getChange().isAbandoned()) {
+ if (!changeData.change().isAbandoned()) {
UiAction.Description descr = new UiAction.Description();
PrivateInternals_UiActionDescription.setId(descr, "followup");
PrivateInternals_UiActionDescription.setMethod(descr, "POST");
diff --git a/java/com/google/gerrit/server/change/AddReviewersOp.java b/java/com/google/gerrit/server/change/AddReviewersOp.java
index ff8e5c6..d05a97c 100644
--- a/java/com/google/gerrit/server/change/AddReviewersOp.java
+++ b/java/com/google/gerrit/server/change/AddReviewersOp.java
@@ -44,7 +44,7 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
@@ -238,7 +238,7 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
opResult =
Result.builder()
.setAddedReviewers(addedReviewers)
@@ -262,7 +262,8 @@
.map(r -> accountCache.get(r.accountId()))
.flatMap(Streams::stream)
.collect(toList());
- reviewerAdded.fire(change, patchSet, reviewers, ctx.getAccount(), ctx.getWhen());
+ reviewerAdded.fire(
+ ctx.getChangeData(change), patchSet, reviewers, ctx.getAccount(), ctx.getWhen());
}
}
diff --git a/java/com/google/gerrit/server/change/AddToAttentionSetOp.java b/java/com/google/gerrit/server/change/AddToAttentionSetOp.java
index 8053b30..a980c32 100644
--- a/java/com/google/gerrit/server/change/AddToAttentionSetOp.java
+++ b/java/com/google/gerrit/server/change/AddToAttentionSetOp.java
@@ -27,7 +27,7 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.util.AttentionSetEmail;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -101,7 +101,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (!notify) {
return;
}
diff --git a/java/com/google/gerrit/server/change/ChangeInserter.java b/java/com/google/gerrit/server/change/ChangeInserter.java
index 6091091..00ef8fa 100644
--- a/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -25,6 +25,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
@@ -63,6 +64,7 @@
import com.google.gerrit.server.mail.send.CreateChangeSender;
import com.google.gerrit.server.mail.send.MessageIdGenerator;
import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gerrit.server.patch.AutoMerger;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -72,6 +74,7 @@
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
import com.google.gerrit.server.update.InsertChangeOp;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.util.CommitMessageUtil;
import com.google.gerrit.server.util.RequestScopePropagator;
@@ -113,6 +116,7 @@
private final ReviewerAdder reviewerAdder;
private final MessageIdGenerator messageIdGenerator;
private final DynamicItem<UrlFormatter> urlFormatter;
+ private final AutoMerger autoMerger;
private final Change.Id changeId;
private final PatchSet.Id psId;
@@ -163,6 +167,7 @@
ReviewerAdder reviewerAdder,
MessageIdGenerator messageIdGenerator,
DynamicItem<UrlFormatter> urlFormatter,
+ AutoMerger autoMerger,
@Assisted Change.Id changeId,
@Assisted ObjectId commitId,
@Assisted String refName) {
@@ -180,6 +185,7 @@
this.reviewerAdder = reviewerAdder;
this.messageIdGenerator = messageIdGenerator;
this.urlFormatter = urlFormatter;
+ this.autoMerger = autoMerger;
this.changeId = changeId;
this.psId = PatchSet.id(changeId, INITIAL_PATCH_SET_ID);
@@ -377,6 +383,15 @@
return;
}
ctx.addRefUpdate(cmd);
+ Optional<ReceiveCommand> autoMerge =
+ autoMerger.createAutoMergeCommitIfNecessary(
+ ctx.getRepoView(),
+ ctx.getRevWalk(),
+ ctx.getInserter(),
+ ctx.getRevWalk().parseCommit(commitId));
+ if (autoMerge.isPresent()) {
+ ctx.addRefUpdate(autoMerge.get());
+ }
}
@Override
@@ -461,7 +476,7 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
reviewerAdditions.postUpdate(ctx);
NotifyResolver.Result notify = ctx.getNotify(change.getId());
if (sendMail && notify.shouldNotify()) {
@@ -514,7 +529,8 @@
* show a transition from an oldValue of 0 to the new value.
*/
if (fireRevisionCreated) {
- revisionCreated.fire(change, patchSet, ctx.getAccount(), ctx.getWhen(), notify);
+ revisionCreated.fire(
+ ctx.getChangeData(change), patchSet, ctx.getAccount(), ctx.getWhen(), notify);
if (approvals != null && !approvals.isEmpty()) {
List<LabelType> labels = projectState.getLabelTypes(change.getDest()).getLabelTypes();
Map<String, Short> allApprovals = new HashMap<>();
@@ -530,7 +546,13 @@
}
}
commentAdded.fire(
- change, patchSet, ctx.getAccount(), null, allApprovals, oldApprovals, ctx.getWhen());
+ ctx.getChangeData(change),
+ patchSet,
+ ctx.getAccount(),
+ null,
+ allApprovals,
+ oldApprovals,
+ ctx.getWhen());
}
}
}
@@ -546,6 +568,7 @@
cmd,
projectState.getProject(),
change.getDest().branch(),
+ ImmutableListMultimap.of(),
ctx.getRepoView().getConfig(),
ctx.getRevWalk().getObjectReader(),
commitId,
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index c7aedb6..0320fc4 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -405,6 +405,10 @@
private void ensureLoaded(Iterable<ChangeData> all) {
if (lazyLoad) {
+ for (ChangeData cd : all) {
+ // Mark all ChangeDatas as coming from the index, but allow backfilling data from NoteDb
+ cd.setStorageConstraint(ChangeData.StorageConstraint.INDEX_PRIMARY_NOTEDB_SECONDARY);
+ }
ChangeData.ensureChangeLoaded(all);
if (has(ALL_REVISIONS)) {
ChangeData.ensureAllPatchSetsLoaded(all);
@@ -417,7 +421,8 @@
ChangeData.ensureCurrentApprovalsLoaded(all);
} else {
for (ChangeData cd : all) {
- cd.setLazyLoad(false);
+ // Mark all ChangeDatas as coming from the index. Disallow using NoteDb
+ cd.setStorageConstraint(ChangeData.StorageConstraint.INDEX_ONLY);
}
}
}
@@ -672,7 +677,7 @@
}
if (has(CURRENT_ACTIONS) || has(CHANGE_ACTIONS)) {
- actionJson.addChangeActions(out, cd.notes());
+ actionJson.addChangeActions(out, cd);
}
if (has(TRACKING_IDS)) {
diff --git a/java/com/google/gerrit/server/change/ChangeResource.java b/java/com/google/gerrit/server/change/ChangeResource.java
index 5a1798d..3729b59 100644
--- a/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/java/com/google/gerrit/server/change/ChangeResource.java
@@ -44,9 +44,10 @@
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
-import com.google.inject.Inject;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@@ -66,6 +67,8 @@
public interface Factory {
ChangeResource create(ChangeNotes notes, CurrentUser user);
+
+ ChangeResource create(ChangeData changeData, CurrentUser user);
}
private static final String ZERO_ID_STRING = ObjectId.zeroId().name();
@@ -77,10 +80,10 @@
private final StarredChangesUtil starredChangesUtil;
private final ProjectCache projectCache;
private final PluginSetContext<ChangeETagComputation> changeETagComputation;
- private final ChangeNotes notes;
+ private final ChangeData changeData;
private final CurrentUser user;
- @Inject
+ @AssistedInject
ChangeResource(
AccountCache accountCache,
ApprovalsUtil approvalUtil,
@@ -89,6 +92,7 @@
StarredChangesUtil starredChangesUtil,
ProjectCache projectCache,
PluginSetContext<ChangeETagComputation> changeETagComputation,
+ ChangeData.Factory changeDataFactory,
@Assisted ChangeNotes notes,
@Assisted CurrentUser user) {
this.accountCache = accountCache;
@@ -98,12 +102,34 @@
this.starredChangesUtil = starredChangesUtil;
this.projectCache = projectCache;
this.changeETagComputation = changeETagComputation;
- this.notes = notes;
+ this.changeData = changeDataFactory.create(notes);
+ this.user = user;
+ }
+
+ @AssistedInject
+ ChangeResource(
+ AccountCache accountCache,
+ ApprovalsUtil approvalUtil,
+ PatchSetUtil patchSetUtil,
+ PermissionBackend permissionBackend,
+ StarredChangesUtil starredChangesUtil,
+ ProjectCache projectCache,
+ PluginSetContext<ChangeETagComputation> changeETagComputation,
+ @Assisted ChangeData changeData,
+ @Assisted CurrentUser user) {
+ this.accountCache = accountCache;
+ this.approvalUtil = approvalUtil;
+ this.patchSetUtil = patchSetUtil;
+ this.permissionBackend = permissionBackend;
+ this.starredChangesUtil = starredChangesUtil;
+ this.projectCache = projectCache;
+ this.changeETagComputation = changeETagComputation;
+ this.changeData = changeData;
this.user = user;
}
public PermissionBackend.ForChange permissions() {
- return permissionBackend.user(user).change(notes);
+ return permissionBackend.user(user).change(getNotes());
}
public CurrentUser getUser() {
@@ -111,7 +137,7 @@
}
public Change.Id getId() {
- return notes.getChangeId();
+ return changeData.getId();
}
/** @return true if {@link #getUser()} is the change's owner. */
@@ -121,7 +147,7 @@
}
public Change getChange() {
- return notes.getChange();
+ return changeData.change();
}
public Project.NameKey getProject() {
@@ -129,7 +155,11 @@
}
public ChangeNotes getNotes() {
- return notes;
+ return changeData.notes();
+ }
+
+ public ChangeData getChangeData() {
+ return changeData;
}
// This includes all information relevant for ETag computation
@@ -153,7 +183,7 @@
accounts.add(getChange().getAssignee());
}
try {
- patchSetUtil.byChange(notes).stream().map(PatchSet::uploader).forEach(accounts::add);
+ patchSetUtil.byChange(getNotes()).stream().map(PatchSet::uploader).forEach(accounts::add);
// It's intentional to include the states for *all* reviewers into the ETag computation.
// We need the states of all current reviewers and CCs because they are part of ChangeInfo.
@@ -162,7 +192,7 @@
// set of accounts that posted a message is too expensive. However everyone who posts a
// message is automatically added as reviewer. Hence if we include removed reviewers we can
// be sure that we have all accounts that posted messages on the change.
- accounts.addAll(approvalUtil.getReviewers(notes).all());
+ accounts.addAll(approvalUtil.getReviewers(getNotes()).all());
} catch (StorageException e) {
// This ETag will be invalidated if it loads next time.
}
@@ -178,7 +208,7 @@
ObjectId noteId;
try {
- noteId = notes.loadRevision();
+ noteId = getNotes().loadRevision();
} catch (StorageException e) {
noteId = null; // This ETag will be invalidated if it loads next time.
}
@@ -194,7 +224,7 @@
changeETagComputation.runEach(
c -> {
- String pluginETag = c.getETag(notes.getProjectName(), notes.getChangeId());
+ String pluginETag = c.getETag(changeData.project(), changeData.getId());
if (pluginETag != null) {
h.putString(pluginETag, UTF_8);
}
@@ -207,8 +237,8 @@
TraceContext.newTimer(
"Compute change ETag",
Metadata.builder()
- .changeId(notes.getChangeId().get())
- .projectName(notes.getProjectName().get())
+ .changeId(changeData.getId().get())
+ .projectName(changeData.project().get())
.build())) {
Hasher h = Hashing.murmur3_128().newHasher();
if (user.isIdentifiedUser()) {
diff --git a/java/com/google/gerrit/server/change/DeleteChangeOp.java b/java/com/google/gerrit/server/change/DeleteChangeOp.java
index 14298d5..c7ddf19 100644
--- a/java/com/google/gerrit/server/change/DeleteChangeOp.java
+++ b/java/com/google/gerrit/server/change/DeleteChangeOp.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.extensions.events.ChangeDeleted;
import com.google.gerrit.server.plugincontext.PluginItemContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.RepoContext;
@@ -49,6 +50,7 @@
private final PatchSetUtil psUtil;
private final StarredChangesUtil starredChangesUtil;
private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
+ private final ChangeData.Factory changeDataFactory;
private final ChangeDeleted changeDeleted;
private final Change.Id id;
@@ -57,11 +59,13 @@
PatchSetUtil psUtil,
StarredChangesUtil starredChangesUtil,
PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore,
+ ChangeData.Factory changeDataFactory,
ChangeDeleted changeDeleted,
@Assisted Change.Id id) {
this.psUtil = psUtil;
this.starredChangesUtil = starredChangesUtil;
this.accountPatchReviewStore = accountPatchReviewStore;
+ this.changeDataFactory = changeDataFactory;
this.changeDeleted = changeDeleted;
this.id = id;
}
@@ -90,7 +94,7 @@
.map(p -> p.commitId().name())
.orElse("n/a")));
ctx.deleteChange();
- changeDeleted.fire(ctx.getChange(), ctx.getAccount(), ctx.getWhen());
+ changeDeleted.fire(changeDataFactory.create(ctx.getChange()), ctx.getAccount(), ctx.getWhen());
return true;
}
diff --git a/java/com/google/gerrit/server/change/DeleteReviewerByEmailOp.java b/java/com/google/gerrit/server/change/DeleteReviewerByEmailOp.java
index 255e13a..2505024 100644
--- a/java/com/google/gerrit/server/change/DeleteReviewerByEmailOp.java
+++ b/java/com/google/gerrit/server/change/DeleteReviewerByEmailOp.java
@@ -24,7 +24,7 @@
import com.google.gerrit.server.mail.send.MessageIdGenerator;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.Collections;
@@ -73,7 +73,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
try {
NotifyResolver.Result notify = ctx.getNotify(change.getId());
if (!notify.shouldNotify()) {
diff --git a/java/com/google/gerrit/server/change/DeleteReviewerOp.java b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
index bf00d27..b1fc67d 100644
--- a/java/com/google/gerrit/server/change/DeleteReviewerOp.java
+++ b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
@@ -46,7 +46,7 @@
import com.google.gerrit.server.project.RemoveReviewerControl;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoView;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -177,7 +177,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
NotifyResolver.Result notify = ctx.getNotify(currChange.getId());
if (input.notify == null
&& currChange.isWorkInProgress()
@@ -195,7 +195,7 @@
logger.atSevere().withCause(err).log("Cannot email update for change %s", currChange.getId());
}
reviewerDeleted.fire(
- currChange,
+ ctx.getChangeData(currChange),
currPs,
reviewer,
ctx.getAccount(),
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java
new file mode 100644
index 0000000..a926147
--- /dev/null
+++ b/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java
@@ -0,0 +1,167 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.change;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.common.FileInfo;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.server.logging.Metadata;
+import com.google.gerrit.server.patch.DiffExecutor;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * Implementation of FileInfoJson which uses {@link FileInfoJsonOldImpl}, but also runs {@link
+ * FileInfoJsonNewImpl} asynchronously and compares the results. This implementation is temporary
+ * and will be used to verify that the results are the same.
+ */
+public class FileInfoJsonComparingImpl implements FileInfoJson {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private final FileInfoJsonOldImpl oldImpl;
+ private final FileInfoJsonNewImpl newImpl;
+ private final ExecutorService executor;
+ private final Metrics metrics;
+
+ /**
+ * TODO(ghareeb): These metrics are temporary for launching the new diff cache redesign and are
+ * not documented. These will be removed soon.
+ */
+ @VisibleForTesting
+ @Singleton
+ static class Metrics {
+ private enum Status {
+ MATCH,
+ MISMATCH,
+ ERROR
+ }
+
+ final Counter1<Status> diffs;
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ diffs =
+ metricMaker.newCounter(
+ "diff/list_files/dark_launch",
+ new Description(
+ "Total number of matching, non-matching, or error in list-files diffs in the old and new diff cache implementations.")
+ .setRate()
+ .setUnit("count"),
+ Field.ofEnum(Status.class, "type", Metadata.Builder::eventType).build());
+ }
+ }
+
+ @Inject
+ public FileInfoJsonComparingImpl(
+ FileInfoJsonOldImpl oldImpl,
+ FileInfoJsonNewImpl newImpl,
+ @DiffExecutor ExecutorService executor,
+ Metrics metrics) {
+ this.oldImpl = oldImpl;
+ this.newImpl = newImpl;
+ this.executor = executor;
+ this.metrics = metrics;
+ }
+
+ @Override
+ public Map<String, FileInfo> getFileInfoMap(
+ Change change, ObjectId objectId, @Nullable PatchSet base)
+ throws ResourceConflictException, PatchListNotAvailableException {
+ Map<String, FileInfo> result = oldImpl.getFileInfoMap(change, objectId, base);
+ @SuppressWarnings("unused")
+ Future<?> ignored =
+ executor.submit(
+ () -> {
+ try {
+ Map<String, FileInfo> fileInfoNew = newImpl.getFileInfoMap(change, objectId, base);
+ compareAndLogMetrics(
+ result,
+ fileInfoNew,
+ String.format(
+ "Mismatch comparing old and new diff implementations for change: %s, objectId: %s and base: %s",
+ change, objectId, base == null ? "none" : base.id()));
+ } catch (ResourceConflictException | PatchListNotAvailableException e) {
+ // If an exception happens while evaluating the new diff, increment the non-matching
+ // counter
+ metrics.diffs.increment(Metrics.Status.ERROR);
+ logger.atWarning().withCause(e).log(
+ "Error comparing old and new diff implementations.");
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public Map<String, FileInfo> getFileInfoMap(
+ Project.NameKey project, ObjectId objectId, int parentNum)
+ throws ResourceConflictException, PatchListNotAvailableException {
+ Map<String, FileInfo> result = oldImpl.getFileInfoMap(project, objectId, parentNum);
+ @SuppressWarnings("unused")
+ Future<?> ignored =
+ executor.submit(
+ () -> {
+ try {
+ Map<String, FileInfo> resultNew =
+ newImpl.getFileInfoMap(project, objectId, parentNum);
+ compareAndLogMetrics(
+ result,
+ resultNew,
+ String.format(
+ "Mismatch comparing old and new diff implementations for project: %s, objectId: %s and parentNum: %d",
+ project, objectId, parentNum));
+ } catch (ResourceConflictException | PatchListNotAvailableException e) {
+ // If an exception happens while evaluating the new diff, increment the non-matching
+ // ctr
+ metrics.diffs.increment(Metrics.Status.ERROR);
+ logger.atWarning().withCause(e).log(
+ "Error comparing old and new diff implementations.");
+ }
+ });
+ return result;
+ }
+
+ private void compareAndLogMetrics(
+ Map<String, FileInfo> fileInfoMapOld,
+ Map<String, FileInfo> fileInfoMapNew,
+ String warningMessage) {
+ if (fileInfoMapOld.equals(fileInfoMapNew)) {
+ metrics.diffs.increment(Metrics.Status.MATCH);
+ return;
+ }
+ metrics.diffs.increment(Metrics.Status.MISMATCH);
+ logger.atWarning().log(
+ warningMessage
+ + "\n"
+ + "Result using old impl: "
+ + fileInfoMapOld
+ + "\n"
+ + "Result using new impl: "
+ + fileInfoMapNew);
+ }
+}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonModule.java b/java/com/google/gerrit/server/change/FileInfoJsonModule.java
index f1c2e80..de116bb 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonModule.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonModule.java
@@ -19,14 +19,25 @@
import org.eclipse.jgit.lib.Config;
public class FileInfoJsonModule extends AbstractModule {
+ /** Use the new diff cache implementation {@link FileInfoJsonNewImpl}. */
private final boolean useNewDiffCache;
+ /** Used to dark launch the new diff cache with the list files endpoint. */
+ private final boolean runNewDiffCacheAsync;
+
public FileInfoJsonModule(@GerritServerConfig Config cfg) {
- this.useNewDiffCache = cfg.getBoolean("cache", "diff_cache", "useNewDiffCache", false);
+ this.useNewDiffCache =
+ cfg.getBoolean("cache", "diff_cache", "runNewDiffCache_ListFiles", false);
+ this.runNewDiffCacheAsync =
+ cfg.getBoolean("cache", "diff_cache", "runNewDiffCacheAsync_listFiles", false);
}
@Override
public void configure() {
+ if (runNewDiffCacheAsync) {
+ bind(FileInfoJson.class).to(FileInfoJsonComparingImpl.class);
+ return;
+ }
bind(FileInfoJson.class)
.to(useNewDiffCache ? FileInfoJsonNewImpl.class : FileInfoJsonOldImpl.class);
}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
index 0d3dcff..1ca2c93 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
@@ -23,6 +23,7 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffOperations;
+import com.google.gerrit.server.patch.FilePathAdapter;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.inject.Inject;
@@ -92,7 +93,7 @@
fileDiff.changeType() != Patch.ChangeType.MODIFIED
? fileDiff.changeType().getCode()
: null;
- fileInfo.oldPath = fileDiff.oldPath().orElse(null);
+ fileInfo.oldPath = FilePathAdapter.getOldPath(fileDiff.oldPath(), fileDiff.changeType());
fileInfo.sizeDelta = fileDiff.sizeDelta();
fileInfo.size = fileDiff.size();
if (fileDiff.patchType().get() == Patch.PatchType.BINARY) {
diff --git a/java/com/google/gerrit/server/change/PatchSetInserter.java b/java/com/google/gerrit/server/change/PatchSetInserter.java
index ef06ea1..df206bd 100644
--- a/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -20,6 +20,7 @@
import static com.google.gerrit.server.project.ProjectCache.illegalState;
import static java.util.Objects.requireNonNull;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
@@ -43,6 +44,7 @@
import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gerrit.server.patch.AutoMerger;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -51,7 +53,7 @@
import com.google.gerrit.server.ssh.NoSshInfo;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
@@ -59,6 +61,7 @@
import java.io.IOException;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.transport.ReceiveCommand;
@@ -81,6 +84,7 @@
private final PatchSetUtil psUtil;
private final WorkInProgressStateChanged wipStateChanged;
private final MessageIdGenerator messageIdGenerator;
+ private final AutoMerger autoMerger;
// Assisted-injected fields.
private final PatchSet.Id psId;
@@ -123,6 +127,7 @@
ProjectCache projectCache,
WorkInProgressStateChanged wipStateChanged,
MessageIdGenerator messageIdGenerator,
+ AutoMerger autoMerger,
@Assisted ChangeNotes notes,
@Assisted PatchSet.Id psId,
@Assisted ObjectId commitId) {
@@ -137,6 +142,7 @@
this.projectCache = projectCache;
this.wipStateChanged = wipStateChanged;
this.messageIdGenerator = messageIdGenerator;
+ this.autoMerger = autoMerger;
this.origNotes = notes;
this.psId = psId;
@@ -213,6 +219,15 @@
throws AuthException, ResourceConflictException, IOException, PermissionBackendException {
validate(ctx);
ctx.addRefUpdate(ObjectId.zeroId(), commitId, getPatchSetId().toRefName());
+ Optional<ReceiveCommand> autoMerge =
+ autoMerger.createAutoMergeCommitIfNecessary(
+ ctx.getRepoView(),
+ ctx.getRevWalk(),
+ ctx.getInserter(),
+ ctx.getRevWalk().parseCommit(commitId));
+ if (autoMerge.isPresent()) {
+ ctx.addRefUpdate(autoMerge.get());
+ }
}
@Override
@@ -283,7 +298,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
NotifyResolver.Result notify = ctx.getNotify(change.getId());
if (notify.shouldNotify() && sendEmail) {
requireNonNull(changeMessage);
@@ -306,11 +321,12 @@
}
if (fireRevisionCreated) {
- revisionCreated.fire(change, patchSet, ctx.getAccount(), ctx.getWhen(), notify);
+ revisionCreated.fire(
+ ctx.getChangeData(change), patchSet, ctx.getAccount(), ctx.getWhen(), notify);
}
if (workInProgress != null && oldWorkInProgressState != workInProgress) {
- wipStateChanged.fire(change, patchSet, ctx.getAccount(), ctx.getWhen());
+ wipStateChanged.fire(ctx.getChangeData(change), patchSet, ctx.getAccount(), ctx.getWhen());
}
}
@@ -342,6 +358,7 @@
.orElseThrow(illegalState(origNotes.getProjectName()))
.getProject(),
origNotes.getChange().getDest().branch(),
+ ImmutableListMultimap.of(),
ctx.getRepoView().getConfig(),
ctx.getRevWalk().getObjectReader(),
commitId,
diff --git a/java/com/google/gerrit/server/change/RebaseChangeOp.java b/java/com/google/gerrit/server/change/RebaseChangeOp.java
index b43996e..aee04ec 100644
--- a/java/com/google/gerrit/server/change/RebaseChangeOp.java
+++ b/java/com/google/gerrit/server/change/RebaseChangeOp.java
@@ -41,7 +41,7 @@
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -270,7 +270,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
patchSetInserter.postUpdate(ctx);
}
diff --git a/java/com/google/gerrit/server/change/RemoveFromAttentionSetOp.java b/java/com/google/gerrit/server/change/RemoveFromAttentionSetOp.java
index e532409..50ee9d4 100644
--- a/java/com/google/gerrit/server/change/RemoveFromAttentionSetOp.java
+++ b/java/com/google/gerrit/server/change/RemoveFromAttentionSetOp.java
@@ -28,7 +28,7 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.util.AttentionSetEmail;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -101,7 +101,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (!notify) {
return;
}
diff --git a/java/com/google/gerrit/server/change/ReviewerAdder.java b/java/com/google/gerrit/server/change/ReviewerAdder.java
index 5d55b4d..1732a2c 100644
--- a/java/com/google/gerrit/server/change/ReviewerAdder.java
+++ b/java/com/google/gerrit/server/change/ReviewerAdder.java
@@ -69,7 +69,7 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
@@ -586,7 +586,7 @@
}
}
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
for (ReviewerAddition addition : additions()) {
if (addition.op != null) {
addition.op.postUpdate(ctx);
diff --git a/java/com/google/gerrit/server/change/RevisionJson.java b/java/com/google/gerrit/server/change/RevisionJson.java
index 558bdba..b702440 100644
--- a/java/com/google/gerrit/server/change/RevisionJson.java
+++ b/java/com/google/gerrit/server/change/RevisionJson.java
@@ -327,7 +327,7 @@
actionJson.addRevisionActions(
changeInfo,
out,
- new RevisionResource(changeResourceFactory.create(cd.notes(), userProvider.get()), in));
+ new RevisionResource(changeResourceFactory.create(cd, userProvider.get()), in));
}
if (gpgApi.isEnabled() && has(PUSH_CERTIFICATES)) {
diff --git a/java/com/google/gerrit/server/change/SetAssigneeOp.java b/java/com/google/gerrit/server/change/SetAssigneeOp.java
index 411c9b6..063e7e0 100644
--- a/java/com/google/gerrit/server/change/SetAssigneeOp.java
+++ b/java/com/google/gerrit/server/change/SetAssigneeOp.java
@@ -30,7 +30,7 @@
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.validators.AssigneeValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
@@ -120,7 +120,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
try {
SetAssigneeSender emailSender =
setAssigneeSenderFactory.create(
@@ -134,6 +134,9 @@
"Cannot send email to new assignee of change %s", change.getId());
}
assigneeChanged.fire(
- change, ctx.getAccount(), oldAssignee != null ? oldAssignee.state() : null, ctx.getWhen());
+ ctx.getChangeData(change),
+ ctx.getAccount(),
+ oldAssignee != null ? oldAssignee.state() : null,
+ ctx.getWhen());
}
}
diff --git a/java/com/google/gerrit/server/change/SetHashtagsOp.java b/java/com/google/gerrit/server/change/SetHashtagsOp.java
index 712e1f3..3e866fa 100644
--- a/java/com/google/gerrit/server/change/SetHashtagsOp.java
+++ b/java/com/google/gerrit/server/change/SetHashtagsOp.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.validators.HashtagValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
@@ -144,10 +144,15 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (updated() && fireEvent) {
hashtagsEdited.fire(
- change, ctx.getAccount(), updatedHashtags, toAdd, toRemove, ctx.getWhen());
+ ctx.getChangeData(change),
+ ctx.getAccount(),
+ updatedHashtags,
+ toAdd,
+ toRemove,
+ ctx.getWhen());
}
}
diff --git a/java/com/google/gerrit/server/change/SetPrivateOp.java b/java/com/google/gerrit/server/change/SetPrivateOp.java
index 382a4f6..5002ee4 100644
--- a/java/com/google/gerrit/server/change/SetPrivateOp.java
+++ b/java/com/google/gerrit/server/change/SetPrivateOp.java
@@ -30,7 +30,7 @@
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -88,9 +88,9 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (!isNoOp) {
- privateStateChanged.fire(change, ps, ctx.getAccount(), ctx.getWhen());
+ privateStateChanged.fire(ctx.getChangeData(change), ps, ctx.getAccount(), ctx.getWhen());
}
}
diff --git a/java/com/google/gerrit/server/change/SetTopicOp.java b/java/com/google/gerrit/server/change/SetTopicOp.java
index c4a49b0..b4ac203 100644
--- a/java/com/google/gerrit/server/change/SetTopicOp.java
+++ b/java/com/google/gerrit/server/change/SetTopicOp.java
@@ -24,7 +24,7 @@
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -81,9 +81,9 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (change != null) {
- topicEdited.fire(change, ctx.getAccount(), oldTopicName, ctx.getWhen());
+ topicEdited.fire(ctx.getChangeData(change), ctx.getAccount(), oldTopicName, ctx.getWhen());
}
}
}
diff --git a/java/com/google/gerrit/server/change/WorkInProgressOp.java b/java/com/google/gerrit/server/change/WorkInProgressOp.java
index f0ebb80..de81010 100644
--- a/java/com/google/gerrit/server/change/WorkInProgressOp.java
+++ b/java/com/google/gerrit/server/change/WorkInProgressOp.java
@@ -30,7 +30,7 @@
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoView;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -126,8 +126,8 @@
}
@Override
- public void postUpdate(Context ctx) {
- stateChanged.fire(change, ps, ctx.getAccount(), ctx.getWhen());
+ public void postUpdate(PostUpdateContext ctx) {
+ stateChanged.fire(ctx.getChangeData(change), ps, ctx.getAccount(), ctx.getWhen());
NotifyResolver.Result notify = ctx.getNotify(change.getId());
if (workInProgress
|| notify.handling().compareTo(NotifyHandling.OWNER_REVIEWERS) < 0
diff --git a/java/com/google/gerrit/server/comment/CommentContextCache.java b/java/com/google/gerrit/server/comment/CommentContextCache.java
index 8c40763..c954a38 100644
--- a/java/com/google/gerrit/server/comment/CommentContextCache.java
+++ b/java/com/google/gerrit/server/comment/CommentContextCache.java
@@ -24,7 +24,7 @@
public interface CommentContextCache {
/**
- * Returns the context lines for a single comment.
+ * Returns the context lines for a single comment. Works for published and draft comments.
*
* @param key a key representing a subset of fields for a comment that serves as an identifier.
* @return a {@link CommentContext} object containing all line numbers and text of the context.
@@ -32,7 +32,8 @@
CommentContext get(CommentContextKey key);
/**
- * Returns the context lines for multiple comments - identified by their {@code keys}.
+ * Returns the context lines for multiple comments - identified by their {@code keys}. Works for
+ * published and draft comments.
*
* @param keys list of keys, where each key represents a single comment through its project,
* change ID, patchset, path and ID. The keys can belong to different projects and changes.
diff --git a/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java b/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
index f44b075..e12b538 100644
--- a/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
+++ b/java/com/google/gerrit/server/comment/CommentContextCacheImpl.java
@@ -68,7 +68,7 @@
@Override
protected void configure() {
persist(CACHE_NAME, CommentContextKey.class, CommentContext.class)
- .version(3)
+ .version(5)
.diskLimit(1 << 30) // limit the total cache size to 1 GB
.maximumWeight(1 << 23) // Limit the size of the in-memory cache to 8 MB
.weigher(CommentContextWeigher.class)
@@ -238,7 +238,8 @@
}
/**
- * Load the comment context for comments of the same project and change ID.
+ * Load the comment context for comments (published and drafts) of the same project and change
+ * ID.
*
* @param keys a list of keys corresponding to some comments
* @param project a gerrit project/repository
@@ -250,10 +251,13 @@
throws IOException {
ChangeNotes notes = notesFactory.createChecked(project, changeId);
List<HumanComment> humanComments = commentsUtil.publishedHumanCommentsByChange(notes);
+ List<HumanComment> drafts = commentsUtil.draftByChange(notes);
+ List<HumanComment> allComments =
+ Streams.concat(humanComments.stream(), drafts.stream()).collect(Collectors.toList());
CommentContextLoader loader = factory.create(project);
Map<ContextInput, CommentContextKey> commentsToKeys = new HashMap<>();
for (CommentContextKey key : keys) {
- Comment comment = getCommentForKey(humanComments, key);
+ Comment comment = getCommentForKey(allComments, key);
commentsToKeys.put(ContextInput.fromComment(comment, key.contextPadding()), key);
}
Map<ContextInput, CommentContext> allContext = loader.getContext(commentsToKeys.keySet());
diff --git a/java/com/google/gerrit/server/comment/CommentContextLoader.java b/java/com/google/gerrit/server/comment/CommentContextLoader.java
index 4a6c956..a5aca48 100644
--- a/java/com/google/gerrit/server/comment/CommentContextLoader.java
+++ b/java/com/google/gerrit/server/comment/CommentContextLoader.java
@@ -33,6 +33,7 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mime.FileTypeRegistry;
import com.google.gerrit.server.patch.ComparisonType;
+import com.google.gerrit.server.patch.SrcContentResolver;
import com.google.gerrit.server.patch.Text;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
@@ -45,7 +46,6 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
@@ -168,9 +168,10 @@
return CommentContext.empty();
}
ObjectId id = tw.getObjectId(0);
- Text src = new Text(repo.open(id, Constants.OBJ_BLOB));
- String contentType = getContentType(tw, filePath, src);
- return createContext(src, commentRange, contextPadding, contentType);
+ byte[] sourceContent = SrcContentResolver.getSourceContent(repo, id, tw.getFileMode(0));
+ Text textSrc = new Text(sourceContent);
+ String contentType = getContentType(tw, filePath, textSrc);
+ return createContext(textSrc, commentRange, contextPadding, contentType);
}
}
diff --git a/java/com/google/gerrit/server/config/CapabilityConstants.java b/java/com/google/gerrit/server/config/CapabilityConstants.java
index 4ab97f8..59819bb 100644
--- a/java/com/google/gerrit/server/config/CapabilityConstants.java
+++ b/java/com/google/gerrit/server/config/CapabilityConstants.java
@@ -39,10 +39,10 @@
public String runAs;
public String runGC;
public String streamEvents;
+ public String viewAccess;
public String viewAllAccounts;
public String viewCaches;
public String viewConnections;
public String viewPlugins;
public String viewQueue;
- public String viewAccess;
}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 52de9d5..3da3fd3 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -130,6 +130,7 @@
import com.google.gerrit.server.git.ReceivePackInitializer;
import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.git.TransferConfig;
+import com.google.gerrit.server.git.receive.PluginPushOption;
import com.google.gerrit.server.git.receive.ReceiveCommitsModule;
import com.google.gerrit.server.git.validators.CommentCountValidator;
import com.google.gerrit.server.git.validators.CommentCumulativeSizeValidator;
@@ -388,6 +389,7 @@
.toInstance(SuggestReviewers.configListener());
DynamicSet.setOf(binder(), ExternalIncludedIn.class);
DynamicMap.mapOf(binder(), ProjectConfigEntry.class);
+ DynamicSet.setOf(binder(), PluginPushOption.class);
DynamicSet.setOf(binder(), PatchSetWebLink.class);
DynamicSet.setOf(binder(), ParentWebLink.class);
DynamicSet.setOf(binder(), FileWebLink.class);
diff --git a/java/com/google/gerrit/server/config/PluginConfigFactory.java b/java/com/google/gerrit/server/config/PluginConfigFactory.java
index a9abd1e..2d0f9a5 100644
--- a/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -289,7 +289,7 @@
*/
public Config getProjectPluginConfigWithInheritance(
Project.NameKey projectName, String pluginName) throws NoSuchProjectException {
- return getPluginConfig(projectName, pluginName).getWithInheritance(false);
+ return getPluginConfig(projectName, pluginName).getWithInheritance(/* merge= */ false);
}
/**
@@ -311,7 +311,7 @@
*/
public Config getProjectPluginConfigWithInheritance(
ProjectState projectState, String pluginName) {
- return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(false);
+ return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(/* merge= */ false);
}
/**
@@ -336,7 +336,7 @@
*/
public Config getProjectPluginConfigWithMergedInheritance(
Project.NameKey projectName, String pluginName) throws NoSuchProjectException {
- return getPluginConfig(projectName, pluginName).getWithInheritance(true);
+ return getPluginConfig(projectName, pluginName).getWithInheritance(/* merge= */ true);
}
/**
@@ -359,7 +359,7 @@
*/
public Config getProjectPluginConfigWithMergedInheritance(
ProjectState projectState, String pluginName) {
- return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(true);
+ return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(/* merge= */ true);
}
private ProjectLevelConfig getPluginConfig(Project.NameKey projectName, String pluginName)
diff --git a/java/com/google/gerrit/server/config/SshClientImplementation.java b/java/com/google/gerrit/server/config/SshClientImplementation.java
new file mode 100644
index 0000000..5811e4d
--- /dev/null
+++ b/java/com/google/gerrit/server/config/SshClientImplementation.java
@@ -0,0 +1,61 @@
+// 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.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Enums;
+import com.google.common.base.Strings;
+
+/* SSH implementation to use by JGit SSH client transport protocol. */
+public enum SshClientImplementation {
+ /** JCraft JSch implementation. */
+ JSCH,
+
+ /** Apache MINA implementation. */
+ APACHE;
+
+ private static final String ENV_VAR = "SSH_CLIENT_IMPLEMENTATION";
+ private static final String SYS_PROP = "gerrit.sshClientImplementation";
+
+ @VisibleForTesting
+ public static SshClientImplementation getFromEnvironment() {
+ String value = System.getenv(ENV_VAR);
+ if (Strings.isNullOrEmpty(value)) {
+ value = System.getProperty(SYS_PROP);
+ }
+ if (Strings.isNullOrEmpty(value)) {
+ return APACHE;
+ }
+ SshClientImplementation client =
+ Enums.getIfPresent(SshClientImplementation.class, value).orNull();
+ if (!Strings.isNullOrEmpty(System.getenv(ENV_VAR))) {
+ checkArgument(
+ client != null, "Invalid value for env variable %s: %s", ENV_VAR, System.getenv(ENV_VAR));
+ } else {
+ checkArgument(
+ client != null,
+ "Invalid value for system property %s: %s",
+ SYS_PROP,
+ System.getProperty(SYS_PROP));
+ }
+ return client;
+ }
+
+ public boolean isMina() {
+ return this == APACHE;
+ }
+}
diff --git a/java/com/google/gerrit/server/events/CommitReceivedEvent.java b/java/com/google/gerrit/server/events/CommitReceivedEvent.java
index eb4d9ee..de355ea 100644
--- a/java/com/google/gerrit/server/events/CommitReceivedEvent.java
+++ b/java/com/google/gerrit/server/events/CommitReceivedEvent.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.events;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.IdentifiedUser;
import java.io.IOException;
@@ -29,6 +30,7 @@
public ReceiveCommand command;
public Project project;
public String refName;
+ public ImmutableListMultimap<String, String> pushOptions;
public Config repoConfig;
public RevWalk revWalk;
public RevCommit commit;
@@ -42,6 +44,7 @@
ReceiveCommand command,
Project project,
String refName,
+ ImmutableListMultimap<String, String> pushOptions,
Config repoConfig,
ObjectReader reader,
ObjectId commitId,
@@ -51,6 +54,7 @@
this.command = command;
this.project = project;
this.refName = refName;
+ this.pushOptions = pushOptions;
this.repoConfig = repoConfig;
this.revWalk = new RevWalk(reader);
this.commit = revWalk.parseCommit(commitId);
diff --git a/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java b/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
index 2189690..e31a1b5 100644
--- a/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.AccountInfo;
@@ -23,6 +22,7 @@
import com.google.gerrit.extensions.events.AssigneeChangedListener;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@@ -42,14 +42,14 @@
}
public void fire(
- Change change, AccountState accountState, AccountState oldAssignee, Timestamp when) {
+ ChangeData changeData, AccountState accountState, AccountState oldAssignee, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
- util.changeInfo(change),
+ util.changeInfo(changeData),
util.accountInfo(accountState),
util.accountInfo(oldAssignee),
when);
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java b/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
index c7a9283..cbe7c6b 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -49,7 +49,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet ps,
AccountState abandoner,
String reason,
@@ -61,8 +61,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), ps),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), ps),
util.accountInfo(abandoner),
reason,
when,
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java b/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
index 1ed6209..23a4583 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.AccountInfo;
@@ -23,6 +22,7 @@
import com.google.gerrit.extensions.events.ChangeDeletedListener;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@@ -41,12 +41,12 @@
this.util = util;
}
- public void fire(Change change, AccountState deleter, Timestamp when) {
+ public void fire(ChangeData changeData, AccountState deleter, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
- Event event = new Event(util.changeInfo(change), util.accountInfo(deleter), when);
+ Event event = new Event(util.changeInfo(changeData), util.accountInfo(deleter), when);
listeners.runEach(l -> l.onChangeDeleted(event));
} catch (StorageException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeMerged.java b/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
index 06d0008..e4896df 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -49,15 +49,19 @@
}
public void fire(
- Change change, PatchSet ps, AccountState merger, String newRevisionId, Timestamp when) {
+ ChangeData changeData,
+ PatchSet ps,
+ AccountState merger,
+ String newRevisionId,
+ Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), ps),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), ps),
util.accountInfo(merger),
newRevisionId,
when);
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeRestored.java b/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
index 1af56d0..8bd222a 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -49,15 +49,15 @@
}
public void fire(
- Change change, PatchSet ps, AccountState restorer, String reason, Timestamp when) {
+ ChangeData changeData, PatchSet ps, AccountState restorer, String reason, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), ps),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), ps),
util.accountInfo(restorer),
reason,
when);
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeReverted.java b/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
index d608c52..4a46eb0 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
@@ -15,12 +15,12 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.ChangeRevertedListener;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@@ -39,12 +39,12 @@
this.util = util;
}
- public void fire(Change change, Change revertChange, Timestamp when) {
+ public void fire(ChangeData changeData, ChangeData revertChangeData, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
- Event event = new Event(util.changeInfo(change), util.changeInfo(revertChange), when);
+ Event event = new Event(util.changeInfo(changeData), util.changeInfo(revertChangeData), when);
listeners.runEach(l -> l.onChangeReverted(event));
} catch (StorageException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
diff --git a/java/com/google/gerrit/server/extensions/events/CommentAdded.java b/java/com/google/gerrit/server/extensions/events/CommentAdded.java
index 151298c..20c54cf 100644
--- a/java/com/google/gerrit/server/extensions/events/CommentAdded.java
+++ b/java/com/google/gerrit/server/extensions/events/CommentAdded.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -30,6 +29,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -51,7 +51,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet ps,
AccountState author,
String comment,
@@ -64,8 +64,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), ps),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), ps),
util.accountInfo(author),
comment,
util.approvals(author, approvals, when),
diff --git a/java/com/google/gerrit/server/extensions/events/EventUtil.java b/java/com/google/gerrit/server/extensions/events/EventUtil.java
index a35140a..f0d038a 100644
--- a/java/com/google/gerrit/server/extensions/events/EventUtil.java
+++ b/java/com/google/gerrit/server/extensions/events/EventUtil.java
@@ -18,7 +18,6 @@
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.client.ListChangesOption;
@@ -84,8 +83,8 @@
this.changeOptions = parseChangeListOptions(gerritConfig);
}
- public ChangeInfo changeInfo(Change change) {
- return changeJsonFactory.create(changeOptions).format(change);
+ public ChangeInfo changeInfo(ChangeData changeData) {
+ return changeJsonFactory.create(changeOptions).format(changeData);
}
public RevisionInfo revisionInfo(Project project, PatchSet ps)
diff --git a/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java b/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
index 5d9c5c2..846257c 100644
--- a/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
+++ b/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
@@ -16,7 +16,6 @@
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.AccountInfo;
@@ -24,6 +23,7 @@
import com.google.gerrit.extensions.events.HashtagsEditedListener;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@@ -45,7 +45,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
AccountState editor,
ImmutableSortedSet<String> hashtags,
Set<String> added,
@@ -57,7 +57,12 @@
try {
Event event =
new Event(
- util.changeInfo(change), util.accountInfo(editor), hashtags, added, removed, when);
+ util.changeInfo(changeData),
+ util.accountInfo(editor),
+ hashtags,
+ added,
+ removed,
+ when);
listeners.runEach(l -> l.onHashtagsEdited(event));
} catch (StorageException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
diff --git a/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java b/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
index bcc6b8e..d81068c 100644
--- a/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -47,15 +47,15 @@
this.util = util;
}
- public void fire(Change change, PatchSet patchSet, AccountState account, Timestamp when) {
+ public void fire(ChangeData changeData, PatchSet patchSet, AccountState account, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), patchSet),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), patchSet),
util.accountInfo(account),
when);
listeners.runEach(l -> l.onPrivateStateChanged(event));
diff --git a/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java b/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
index 35e7828..ba73ca1 100644
--- a/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
+++ b/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
@@ -16,7 +16,6 @@
import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -30,6 +29,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -51,7 +51,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet patchSet,
List<AccountState> reviewers,
AccountState adder,
@@ -63,8 +63,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), patchSet),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), patchSet),
Lists.transform(reviewers, util::accountInfo),
util.accountInfo(adder),
when);
diff --git a/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java b/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
index 147f980..80037bc 100644
--- a/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -30,6 +29,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -51,7 +51,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet patchSet,
AccountState reviewer,
AccountState remover,
@@ -66,8 +66,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), patchSet),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), patchSet),
util.accountInfo(reviewer),
util.accountInfo(remover),
message,
diff --git a/java/com/google/gerrit/server/extensions/events/RevisionCreated.java b/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
index 8179e9a..4c78216 100644
--- a/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
+++ b/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -30,6 +29,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -44,7 +44,7 @@
new RevisionCreated() {
@Override
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet patchSet,
AccountState uploader,
Timestamp when,
@@ -66,7 +66,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet patchSet,
AccountState uploader,
Timestamp when,
@@ -77,8 +77,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), patchSet),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), patchSet),
util.accountInfo(uploader),
when,
notify.handling());
diff --git a/java/com/google/gerrit/server/extensions/events/TopicEdited.java b/java/com/google/gerrit/server/extensions/events/TopicEdited.java
index e4089b1..08b47f1 100644
--- a/java/com/google/gerrit/server/extensions/events/TopicEdited.java
+++ b/java/com/google/gerrit/server/extensions/events/TopicEdited.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.AccountInfo;
@@ -23,6 +22,7 @@
import com.google.gerrit.extensions.events.TopicEditedListener;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@@ -41,13 +41,14 @@
this.util = util;
}
- public void fire(Change change, AccountState account, String oldTopicName, Timestamp when) {
+ public void fire(
+ ChangeData changeData, AccountState account, String oldTopicName, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
- new Event(util.changeInfo(change), util.accountInfo(account), oldTopicName, when);
+ new Event(util.changeInfo(changeData), util.accountInfo(account), oldTopicName, when);
listeners.runEach(l -> l.onTopicEdited(event));
} catch (StorageException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
diff --git a/java/com/google/gerrit/server/extensions/events/VoteDeleted.java b/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
index ef4e461..244e46c 100644
--- a/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -30,6 +29,7 @@
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -51,7 +51,7 @@
}
public void fire(
- Change change,
+ ChangeData changeData,
PatchSet ps,
AccountState reviewer,
Map<String, Short> approvals,
@@ -66,8 +66,8 @@
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), ps),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), ps),
util.accountInfo(reviewer),
util.approvals(remover, approvals, when),
util.approvals(remover, oldApprovals, when),
diff --git a/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java b/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
index 06b244b..bfc068d 100644
--- a/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.extensions.events;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -41,7 +41,8 @@
public static final WorkInProgressStateChanged DISABLED =
new WorkInProgressStateChanged() {
@Override
- public void fire(Change change, PatchSet patchSet, AccountState account, Timestamp when) {}
+ public void fire(
+ ChangeData changeData, PatchSet patchSet, AccountState account, Timestamp when) {}
};
private final PluginSetContext<WorkInProgressStateChangedListener> listeners;
@@ -59,15 +60,15 @@
this.util = null;
}
- public void fire(Change change, PatchSet patchSet, AccountState account, Timestamp when) {
+ public void fire(ChangeData changeData, PatchSet patchSet, AccountState account, Timestamp when) {
if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
- util.changeInfo(change),
- util.revisionInfo(change.getProject(), patchSet),
+ util.changeInfo(changeData),
+ util.revisionInfo(changeData.project(), patchSet),
util.accountInfo(account),
when);
listeners.runEach(l -> l.onWorkInProgressStateChanged(event));
diff --git a/java/com/google/gerrit/server/git/CommitUtil.java b/java/com/google/gerrit/server/git/CommitUtil.java
index 47cbd60..272ae65 100644
--- a/java/com/google/gerrit/server/git/CommitUtil.java
+++ b/java/com/google/gerrit/server/git/CommitUtil.java
@@ -48,7 +48,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.CommitMessageUtil;
import com.google.inject.Inject;
@@ -310,8 +310,9 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
- changeReverted.fire(change, ins.getChange(), ctx.getWhen());
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
+ changeReverted.fire(
+ ctx.getChangeData(change), ctx.getChangeData(ins.getChange()), ctx.getWhen());
try {
RevertedSender emailSender = revertedSenderFactory.create(ctx.getProject(), change.getId());
emailSender.setFrom(ctx.getAccountId());
diff --git a/java/com/google/gerrit/server/git/GitRepositoryManager.java b/java/com/google/gerrit/server/git/GitRepositoryManager.java
index 2697eee..e4d0696 100644
--- a/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -57,4 +57,13 @@
/** @return set of all known projects, sorted by natural NameKey order. */
SortedSet<Project.NameKey> list();
+
+ /**
+ * Check if garbage collection can be performed by the repository manager.
+ *
+ * @return true if repository can perform garbage collection.
+ */
+ default Boolean canPerformGC() {
+ return false;
+ }
}
diff --git a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index bf5a0fd..10220d8 100644
--- a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -199,6 +199,11 @@
}
}
+ @Override
+ public Boolean canPerformGC() {
+ return true;
+ }
+
private boolean isUnreasonableName(Project.NameKey nameKey) {
final String name = nameKey.get();
diff --git a/java/com/google/gerrit/server/git/MergedByPushOp.java b/java/com/google/gerrit/server/git/MergedByPushOp.java
index 78cb013..b6cb30df 100644
--- a/java/com/google/gerrit/server/git/MergedByPushOp.java
+++ b/java/com/google/gerrit/server/git/MergedByPushOp.java
@@ -33,7 +33,7 @@
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -178,7 +178,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (!correctBranch) {
return;
}
@@ -214,7 +214,8 @@
}
}));
- changeMerged.fire(change, patchSet, ctx.getAccount(), mergeResultRevId, ctx.getWhen());
+ changeMerged.fire(
+ ctx.getChangeData(change), patchSet, ctx.getAccount(), mergeResultRevId, ctx.getWhen());
}
private PatchSetInfo getPatchSetInfo(ChangeContext ctx) throws IOException {
diff --git a/java/com/google/gerrit/server/git/TagSet.java b/java/com/google/gerrit/server/git/TagSet.java
index d6220a2..57fcf71 100644
--- a/java/com/google/gerrit/server/git/TagSet.java
+++ b/java/com/google/gerrit/server/git/TagSet.java
@@ -43,6 +43,17 @@
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;
+/**
+ * Builds a set of tags, and tracks which tags are reachable from which non-tag, non-special refs.
+ * An instance is constructed from a snapshot of the ref database. TagSets can be incrementally
+ * updated to newer states of the RefDatabase using the refresh method. The updateFastForward method
+ * can do partial updates based on individual refs moving forward.
+ *
+ * <p>This set is used to determine which tags should be advertised when only a subset of refs is
+ * visible to a user.
+ *
+ * <p>TagSets can be serialized for use in a persisted TagCache
+ */
class TagSet {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final ImmutableSet<String> SKIPPABLE_REF_PREFIXES =
@@ -53,7 +64,14 @@
RefNames.REFS_STARRED_CHANGES);
private final Project.NameKey projectName;
+
+ /**
+ * refName => ref. CachedRef is a ref that has an integer identity, used for indexing into
+ * BitSets.
+ */
private final Map<String, CachedRef> refs;
+
+ /** ObjectId-pointed-to-by-tag => Tag */
private final ObjectIdOwnerMap<Tag> tags;
TagSet(Project.NameKey projectName) {
@@ -86,13 +104,16 @@
return tags;
}
+ /** Record a fast-forward update of the given ref. This is called from multiple threads. */
boolean updateFastForward(String refName, ObjectId oldValue, ObjectId newValue) {
+ // this looks fishy: refs is not a thread-safe data structure, but it is mutated in build() and
+ // rebuild(). TagSetHolder prohibits concurrent writes through the buildLock mutex, but it does
+ // not prohibit concurrent read/write.
CachedRef ref = refs.get(refName);
if (ref != null) {
// compareAndSet works on reference equality, but this operation
// wants to use object equality. Switch out oldValue with cur so the
// compareAndSet will function correctly for this operation.
- //
ObjectId cur = ref.get();
if (cur.equals(oldValue)) {
return ref.compareAndSet(cur, newValue);
@@ -391,6 +412,9 @@
}
static final class Tag extends ObjectIdOwnerMap.Entry {
+
+ // a RefCache.flag => isVisible map. This reference is aliased to the
+ // bitset in TagCommit.refFlags.
@VisibleForTesting final BitSet refFlags;
Tag(AnyObjectId id, BitSet flags) {
@@ -407,11 +431,12 @@
return MoreObjects.toStringHelper(this).addValue(name()).add("refFlags", refFlags).toString();
}
}
-
+ /** A ref along with its index into BitSet. */
@VisibleForTesting
static final class CachedRef extends AtomicReference<ObjectId> {
private static final long serialVersionUID = 1L;
+ /** unique identifier for this ref within the TagSet. */
final int flag;
CachedRef(Ref ref, int flag) {
@@ -444,7 +469,9 @@
}
}
+ // TODO(hanwen): this would be better named as CommitWithReachability, as it also holds non-tags.
private static final class TagCommit extends RevCommit {
+ /** CachedRef.flag => isVisible, indicating if this commit is reachable from the ref. */
final BitSet refFlags;
TagCommit(AnyObjectId id) {
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index 2177485..d037994 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -296,7 +296,7 @@
REPOSITORY_SIZE_GROUP, projectName);
throw new RuntimeException(e);
}
- availableTokens.availableTokens().ifPresent(v -> receivePack.setMaxObjectSizeLimit(v));
+ availableTokens.availableTokens().ifPresent(receivePack::setMaxPackSizeLimit);
}
/** Determine if the user can upload commits. */
diff --git a/java/com/google/gerrit/server/git/receive/BranchCommitValidator.java b/java/com/google/gerrit/server/git/receive/BranchCommitValidator.java
index 55261223..f680b7b 100644
--- a/java/com/google/gerrit/server/git/receive/BranchCommitValidator.java
+++ b/java/com/google/gerrit/server/git/receive/BranchCommitValidator.java
@@ -19,6 +19,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.BranchNameKey;
@@ -109,12 +110,13 @@
ObjectReader objectReader,
ReceiveCommand cmd,
RevCommit commit,
+ ImmutableListMultimap<String, String> pushOptions,
boolean isMerged,
NoteMap rejectCommits,
@Nullable Change change)
throws IOException {
return validateCommit(
- repository, objectReader, cmd, commit, isMerged, rejectCommits, change, false);
+ repository, objectReader, cmd, commit, pushOptions, isMerged, rejectCommits, change, false);
}
/**
@@ -134,6 +136,7 @@
ObjectReader objectReader,
ReceiveCommand cmd,
RevCommit commit,
+ ImmutableListMultimap<String, String> pushOptions,
boolean isMerged,
NoteMap rejectCommits,
@Nullable Change change,
@@ -146,6 +149,7 @@
cmd,
project,
branch.branch(),
+ pushOptions,
new Config(repository.getConfig()),
objectReader,
commit,
diff --git a/java/com/google/gerrit/server/git/receive/PluginPushOption.java b/java/com/google/gerrit/server/git/receive/PluginPushOption.java
new file mode 100644
index 0000000..788df70
--- /dev/null
+++ b/java/com/google/gerrit/server/git/receive/PluginPushOption.java
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git.receive;
+
+/**
+ * Push option that can be specified on push.
+ *
+ * <p>On push the option has to be specified as {@code -o <pluginName>~<name>=<value>}, or if a
+ * value is not required as {@code -o <pluginName>~<name>}.
+ */
+public interface PluginPushOption {
+ /** The name of the push option. */
+ public String getName();
+
+ /** The description of the push option. */
+ public String getDescription();
+}
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 4c90ef9..633a407 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.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.common.collect.ImmutableListMultimap.toImmutableListMultimap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.flogger.LazyArgs.lazy;
import static com.google.gerrit.entities.RefNames.REFS_CHANGES;
@@ -48,6 +49,7 @@
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -146,6 +148,7 @@
import com.google.gerrit.server.mail.MailUtil.MailRecipients;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.Sequences;
+import com.google.gerrit.server.patch.AutoMerger;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.GlobalPermission;
@@ -169,7 +172,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.update.RepoOnlyOp;
import com.google.gerrit.server.update.RetryHelper;
@@ -211,6 +214,7 @@
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -326,6 +330,7 @@
private final CreateGroupPermissionSyncer createGroupPermissionSyncer;
private final CreateRefControl createRefControl;
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
+ private final DynamicSet<PluginPushOption> pluginPushOptions;
private final PluginSetContext<ReceivePackInitializer> initializers;
private final MergedByPushOp.Factory mergedByPushOpFactory;
private final PatchSetInfoFactory patchSetInfoFactory;
@@ -352,6 +357,7 @@
private final SetPrivateOp.Factory setPrivateOpFactory;
private final ReplyAttentionSetUpdates replyAttentionSetUpdates;
private final DynamicItem<UrlFormatter> urlFormatter;
+ private final AutoMerger autoMerger;
// Assisted injected fields.
private final ProjectState projectState;
@@ -408,6 +414,7 @@
CreateGroupPermissionSyncer createGroupPermissionSyncer,
CreateRefControl createRefControl,
DynamicMap<ProjectConfigEntry> pluginConfigEntries,
+ DynamicSet<PluginPushOption> pluginPushOptions,
PluginSetContext<ReceivePackInitializer> initializers,
PluginSetContext<CommentValidator> commentValidators,
MergedByPushOp.Factory mergedByPushOpFactory,
@@ -435,6 +442,7 @@
SetPrivateOp.Factory setPrivateOpFactory,
ReplyAttentionSetUpdates replyAttentionSetUpdates,
DynamicItem<UrlFormatter> urlFormatter,
+ AutoMerger autoMerger,
@Assisted ProjectState projectState,
@Assisted IdentifiedUser user,
@Assisted ReceivePack rp,
@@ -467,6 +475,7 @@
this.patchSetInfoFactory = patchSetInfoFactory;
this.permissionBackend = permissionBackend;
this.pluginConfigEntries = pluginConfigEntries;
+ this.pluginPushOptions = pluginPushOptions;
this.projectCache = projectCache;
this.psUtil = psUtil;
this.performanceLoggers = performanceLoggers;
@@ -485,6 +494,7 @@
this.setPrivateOpFactory = setPrivateOpFactory;
this.replyAttentionSetUpdates = replyAttentionSetUpdates;
this.urlFormatter = urlFormatter;
+ this.autoMerger = autoMerger;
// Assisted injected fields.
this.projectState = projectState;
@@ -1788,8 +1798,13 @@
String ref;
magicBranch.cmdLineParser = optionParserFactory.create(magicBranch);
+ // Filter out plugin push options, as the parser would reject them as unknown.
+ ImmutableListMultimap<String, String> pushOptionsToParse =
+ pushOptions.entries().stream()
+ .filter(e -> !isPluginPushOption(e.getKey()))
+ .collect(toImmutableListMultimap(e -> e.getKey(), e -> e.getValue()));
try {
- ref = magicBranch.parse(pushOptions);
+ ref = magicBranch.parse(pushOptionsToParse);
} catch (CmdLineException e) {
if (!magicBranch.cmdLineParser.wasHelpRequestedByOption()) {
logger.atFine().log("Invalid branch syntax");
@@ -1808,6 +1823,20 @@
StringWriter w = new StringWriter();
w.write("\nHelp for refs/for/branch:\n\n");
magicBranch.cmdLineParser.printUsage(w, null);
+
+ String pluginPushOptionsHelp =
+ StreamSupport.stream(pluginPushOptions.entries().spliterator(), /* parallel= */ false)
+ .map(
+ e ->
+ String.format(
+ "-o %s~%s: %s",
+ e.getPluginName(), e.get().getName(), e.get().getDescription()))
+ .sorted()
+ .collect(joining("\n"));
+ if (!pluginPushOptionsHelp.isEmpty()) {
+ w.write("\nPlugin push options:\n" + pluginPushOptionsHelp);
+ }
+
addMessage(w.toString());
reject(cmd, "see help");
return;
@@ -1972,6 +2001,11 @@
}
}
+ private boolean isPluginPushOption(String pushOptionName) {
+ return StreamSupport.stream(pluginPushOptions.entries().spliterator(), /* parallel= */ false)
+ .anyMatch(e -> pushOptionName.equals(e.getPluginName() + "~" + e.get().getName()));
+ }
+
// Validate that the new commits are connected with the target
// branch. If they aren't, we want to abort. We do this check by
// looking to see if we can compute a merge base between the new
@@ -2219,6 +2253,7 @@
receivePack.getRevWalk().getObjectReader(),
magicBranch.cmd,
c,
+ ImmutableListMultimap.copyOf(pushOptions),
magicBranch.merged,
rejectCommits,
null);
@@ -3032,6 +3067,25 @@
if (progress != null) {
bu.addOp(notes.getChangeId(), new ChangeProgressOp(progress));
}
+ bu.addRepoOnlyOp(
+ new RepoOnlyOp() {
+ @Override
+ public void updateRepo(RepoContext ctx) throws Exception {
+ // Create auto merge ref if the new patch set is a merge commit. This is only
+ // required for new patch sets on existing changes as these do not go through
+ // PatchSetInserter. New changes pushed via git go through ChangeInserter and have
+ // their auto merge commits created there.
+ Optional<ReceiveCommand> autoMerge =
+ autoMerger.createAutoMergeCommitIfNecessary(
+ ctx.getRepoView(),
+ ctx.getRevWalk(),
+ ctx.getInserter(),
+ ctx.getRevWalk().parseCommit(newCommitId));
+ if (autoMerge.isPresent()) {
+ ctx.addRefUpdate(autoMerge.get());
+ }
+ }
+ });
}
}
@@ -3089,7 +3143,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
String refName = cmd.getRefName();
if (cmd.getType() == ReceiveCommand.Type.UPDATE) { // aka fast-forward
logger.atFine().log("Updating tag cache on fast-forward of %s", cmd.getRefName());
@@ -3231,7 +3285,15 @@
BranchCommitValidator.Result validationResult =
validator.validateCommit(
- repo, walk.getObjectReader(), cmd, c, false, rejectCommits, null, skipValidation);
+ repo,
+ walk.getObjectReader(),
+ cmd,
+ c,
+ ImmutableListMultimap.copyOf(pushOptions),
+ false,
+ rejectCommits,
+ null,
+ skipValidation);
messages.addAll(validationResult.messages());
if (!validationResult.isValid()) {
break;
diff --git a/java/com/google/gerrit/server/git/receive/ReplaceOp.java b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
index ce62d7a..75ee311 100644
--- a/java/com/google/gerrit/server/git/receive/ReplaceOp.java
+++ b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
@@ -74,6 +74,7 @@
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.gerrit.server.validators.ValidationException;
@@ -493,7 +494,7 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
reviewerAdditions.postUpdate(ctx);
if (changeKind != ChangeKind.TRIVIAL_REBASE) {
// TODO(dborowitz): Merge email templates so we only have to send one.
@@ -506,7 +507,8 @@
}
}
NotifyResolver.Result notify = ctx.getNotify(notes.getChangeId());
- revisionCreated.fire(notes.getChange(), newPatchSet, ctx.getAccount(), ctx.getWhen(), notify);
+ revisionCreated.fire(
+ ctx.getChangeData(notes), newPatchSet, ctx.getAccount(), ctx.getWhen(), notify);
try {
fireApprovalsEvent(ctx);
} catch (Exception e) {
@@ -560,7 +562,7 @@
}
}
- private void fireApprovalsEvent(Context ctx) {
+ private void fireApprovalsEvent(PostUpdateContext ctx) {
if (approvals.isEmpty()) {
return;
}
@@ -588,7 +590,7 @@
}
}
commentAdded.fire(
- notes.getChange(),
+ ctx.getChangeData(notes),
newPatchSet,
ctx.getAccount(),
null,
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index c67df8b..1cb0bea 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -56,11 +56,11 @@
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.ssh.HostKey;
import com.google.gerrit.server.ssh.SshInfo;
import com.google.gerrit.server.util.MagicBranch;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.jcraft.jsch.HostKey;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -234,7 +234,7 @@
List<CommitValidationMessage> messages = new ArrayList<>();
try {
for (CommitValidationListener commitValidator : validators) {
- try (TraceTimer traceTimer =
+ try (TraceTimer ignored =
TraceContext.newTimer(
"Running CommitValidationListener",
Metadata.builder()
@@ -330,7 +330,7 @@
} else if (idList.size() > 1) {
throw new CommitValidationException(MULTIPLE_CHANGE_ID_MSG, messages);
} else {
- String v = idList.get(idList.size() - 1).trim();
+ String v = idList.get(0).trim();
// Reject Change-Ids with wrong format and invalid placeholder ID from
// Egit (I0000000000000000000000000000000000000000).
if (!CHANGE_ID.matcher(v).matches() || v.matches("^I00*$")) {
@@ -450,10 +450,11 @@
private long countChangedFiles(CommitReceivedEvent receiveEvent) throws IOException {
try (Repository repository = repoManager.openRepository(receiveEvent.project.getNameKey());
- RevWalk revWalk = new RevWalk(repository);
DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) {
- diffFormatter.setReader(revWalk.getObjectReader(), repository.getConfig());
- diffFormatter.setDetectRenames(true);
+ diffFormatter.setRepository(repository);
+ // Do not detect renames; that would require reading file contents, which is slow for large
+ // files.
+ diffFormatter.setDetectRenames(false);
// For merge commits, i.e. >1 parents, we use parent #0 by convention.
List<DiffEntry> diffEntries =
diffFormatter.scan(
@@ -554,7 +555,7 @@
/** Execute commit validation plug-ins */
public static class PluginCommitValidationListener implements CommitValidationListener {
- private boolean skipValidation;
+ private final boolean skipValidation;
private final PluginSetContext<CommitValidationListener> commitValidationListeners;
public PluginCommitValidationListener(
@@ -596,7 +597,8 @@
@Override
public boolean shouldValidateAllCommits() {
- return commitValidationListeners.stream().anyMatch(v -> v.shouldValidateAllCommits());
+ return commitValidationListeners.stream()
+ .anyMatch(CommitValidationListener::shouldValidateAllCommits);
}
}
diff --git a/java/com/google/gerrit/server/group/GroupResolver.java b/java/com/google/gerrit/server/group/GroupResolver.java
index 50ec893..546614c 100644
--- a/java/com/google/gerrit/server/group/GroupResolver.java
+++ b/java/com/google/gerrit/server/group/GroupResolver.java
@@ -18,6 +18,7 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
diff --git a/java/com/google/gerrit/server/group/InternalGroupDescription.java b/java/com/google/gerrit/server/group/InternalGroupDescription.java
index 740557a..62ebcfe 100644
--- a/java/com/google/gerrit/server/group/InternalGroupDescription.java
+++ b/java/com/google/gerrit/server/group/InternalGroupDescription.java
@@ -22,6 +22,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import java.sql.Timestamp;
public class InternalGroupDescription implements GroupDescription.Internal {
diff --git a/java/com/google/gerrit/server/group/db/GroupConfig.java b/java/com/google/gerrit/server/group/db/GroupConfig.java
index 60a1e3e..b2d1849b 100644
--- a/java/com/google/gerrit/server/group/db/GroupConfig.java
+++ b/java/com/google/gerrit/server/group/db/GroupConfig.java
@@ -24,14 +24,15 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.util.time.TimeUtil;
import java.io.IOException;
import java.sql.Timestamp;
@@ -156,7 +157,7 @@
Project.NameKey projectName,
Repository repository,
AccountGroup.UUID groupUuid,
- ObjectId groupRefObjectId)
+ @Nullable ObjectId groupRefObjectId)
throws IOException, ConfigInvalidException {
GroupConfig groupConfig = new GroupConfig(groupUuid);
if (groupRefObjectId == null) {
diff --git a/java/com/google/gerrit/server/group/db/GroupConfigCommitMessage.java b/java/com/google/gerrit/server/group/db/GroupConfigCommitMessage.java
index 5627154..77c284a 100644
--- a/java/com/google/gerrit/server/group/db/GroupConfigCommitMessage.java
+++ b/java/com/google/gerrit/server/group/db/GroupConfigCommitMessage.java
@@ -17,7 +17,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.entities.InternalGroup;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
diff --git a/java/com/google/gerrit/server/group/db/GroupConfigEntry.java b/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
index 81f5c7e..be56344 100644
--- a/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
+++ b/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
@@ -16,7 +16,7 @@
import com.google.common.base.Strings;
import com.google.gerrit.entities.AccountGroup;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.entities.InternalGroup;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
diff --git a/java/com/google/gerrit/server/group/db/Groups.java b/java/com/google/gerrit/server/group/db/Groups.java
index 90a5a1f..30e37cb 100644
--- a/java/com/google/gerrit/server/group/db/Groups.java
+++ b/java/com/google/gerrit/server/group/db/Groups.java
@@ -17,13 +17,14 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.AccountGroupByIdAudit;
import com.google.gerrit.entities.AccountGroupMemberAudit;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -80,6 +81,23 @@
}
/**
+ * Returns the {@code InternalGroup} for the specified UUID and groupRefObjectId
+ *
+ * @param groupUuid the UUID of the group
+ * @param groupRefObjectId the ref revision of this group
+ * @return the found {@code InternalGroup} if it exists, or else an empty {@code Optional}
+ * @throws IOException if the group couldn't be retrieved from NoteDb
+ * @throws ConfigInvalidException if the group couldn't be retrieved from NoteDb
+ */
+ public Optional<InternalGroup> getGroup(
+ AccountGroup.UUID groupUuid, @Nullable ObjectId groupRefObjectId)
+ throws IOException, ConfigInvalidException {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
+ return getGroupFromNoteDb(allUsersName, allUsersRepo, groupUuid, groupRefObjectId);
+ }
+ }
+
+ /**
* Loads an internal group from NoteDb using the group UUID. This method returns the latest state
* of the internal group.
*/
@@ -97,7 +115,7 @@
AllUsersName allUsersName,
Repository allUsersRepository,
AccountGroup.UUID uuid,
- ObjectId groupRefObjectId)
+ @Nullable ObjectId groupRefObjectId)
throws IOException, ConfigInvalidException {
GroupConfig groupConfig =
GroupConfig.loadForGroup(allUsersName, allUsersRepository, uuid, groupRefObjectId);
diff --git a/java/com/google/gerrit/server/group/db/GroupsConsistencyChecker.java b/java/com/google/gerrit/server/group/db/GroupsConsistencyChecker.java
index 8a6cd94..732712e 100644
--- a/java/com/google/gerrit/server/group/db/GroupsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/group/db/GroupsConsistencyChecker.java
@@ -19,13 +19,13 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.Accounts;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
diff --git a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
index 35f5dea..01ee811 100644
--- a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
+++ b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
@@ -25,11 +25,11 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
diff --git a/java/com/google/gerrit/server/group/db/GroupsUpdate.java b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
index 4ec5c36..02d55eb 100644
--- a/java/com/google/gerrit/server/group/db/GroupsUpdate.java
+++ b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
@@ -23,6 +23,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.exceptions.NoSuchGroupException;
@@ -39,7 +40,6 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.group.GroupAuditService;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
diff --git a/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java b/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
index 9e6539a..5c7408c 100644
--- a/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
+++ b/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
@@ -101,7 +101,7 @@
*
* <p>If this {@code InternalGroupUpdate} is passed next to an {@link InternalGroupCreation}
* during a group creation, this {@code Timestamp} is used for the NoteDb commits of the new
- * group. Hence, the {@link com.google.gerrit.server.group.InternalGroup#getCreatedOn()
+ * group. Hence, the {@link com.google.gerrit.entities.InternalGroup#getCreatedOn()
* InternalGroup#getCreatedOn()} field will match this {@code Timestamp}.
*
* <p><strong>Note: </strong>{@code Timestamp}s of NoteDb commits for groups are used for events
diff --git a/java/com/google/gerrit/server/group/testing/InternalGroupSubject.java b/java/com/google/gerrit/server/group/testing/InternalGroupSubject.java
index 8f20e92..8a1221e 100644
--- a/java/com/google/gerrit/server/group/testing/InternalGroupSubject.java
+++ b/java/com/google/gerrit/server/group/testing/InternalGroupSubject.java
@@ -23,7 +23,7 @@
import com.google.common.truth.StringSubject;
import com.google.common.truth.Subject;
import com.google.gerrit.entities.AccountGroup;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.entities.InternalGroup;
import java.sql.Timestamp;
import org.eclipse.jgit.lib.ObjectId;
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index 13fc066..9a0ae75 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -820,7 +820,7 @@
});
public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_LENIENT =
- SubmitRuleOptions.builder().allowClosed(true).build();
+ SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build();
public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_STRICT =
SubmitRuleOptions.builder().build();
@@ -922,11 +922,6 @@
public static void parseSubmitRecords(
Collection<String> values, SubmitRuleOptions opts, ChangeData out) {
List<SubmitRecord> records = parseSubmitRecords(values);
- if (records.isEmpty()) {
- // Assume no values means the field is not in the index;
- // SubmitRuleEvaluator ensures the list is non-empty.
- return;
- }
out.setSubmitRecords(opts, records);
}
diff --git a/java/com/google/gerrit/server/index/change/ChangeIndexer.java b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
index e0f6bec..f7f0f33 100644
--- a/java/com/google/gerrit/server/index/change/ChangeIndexer.java
+++ b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
@@ -46,6 +46,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
@@ -79,8 +80,7 @@
private final StalenessChecker stalenessChecker;
private final boolean autoReindexIfStale;
- private final Set<IndexTask> queuedIndexTasks =
- Collections.newSetFromMap(new ConcurrentHashMap<>());
+ private final Map<Change.Id, IndexTask> queuedIndexTasks = new ConcurrentHashMap<>();
private final Set<ReindexIfStaleTask> queuedReindexIfStaleTasks =
Collections.newSetFromMap(new ConcurrentHashMap<>());
@@ -137,16 +137,44 @@
/**
* Start indexing a change.
*
- * @param id change to index.
+ * @param changeId change to index.
* @return future for the indexing task.
*/
- public ListenableFuture<?> indexAsync(Project.NameKey project, Change.Id id) {
- IndexTask task = new IndexTask(project, id);
- if (queuedIndexTasks.add(task)) {
- fireChangeScheduledForIndexingEvent(project.get(), id.get());
- return submit(task);
- }
- return Futures.immediateFuture(null);
+ public ListenableFuture<ChangeData> indexAsync(Project.NameKey project, Change.Id changeId) {
+ // If the change was already scheduled for indexing, we do not need to schedule it again. Change
+ // updates that happened after the change was scheduled for indexing will automatically be taken
+ // into account when the index task is executed (as it reads the current change state).
+ // To skip duplicate index requests, queuedIndexTasks keeps track of the scheduled index tasks.
+ // Here we check if the change has already been scheduled for indexing, and only if not we
+ // create a new index task for the change.
+ // By using computeIfAbsent we ensure that the lookup and the insertion of a new task happens
+ // atomically. Some attempted update operations on this map by other threads may be blocked
+ // while the computation is in progress (but not all as ConcurrentHashMap doesn't lock the
+ // entire table on write, but only segments of the table).
+ IndexTask task =
+ queuedIndexTasks.computeIfAbsent(
+ changeId,
+ id -> {
+ fireChangeScheduledForIndexingEvent(project.get(), id.get());
+ return new IndexTask(project, id);
+ });
+ // Submitting the task to the executor must not happen from within the computeIfAbsent callback,
+ // as this could result in the task being executed before the computeIfAbsent method has
+ // finished (e.g. if a direct executor is used, but also if starting the task asynchronously is
+ // faster than finishing the computeIfAbsent method). This could lead to failures and unexpected
+ // behavior:
+ // * The first thing that IndexTask does is to remove itself from queuedIndexTasks.
+ // This is done so that index requests which are received while an index task for the same
+ // change is in progress, are not dropped but added to the queue. This is important since
+ // the change state that is written to the index is read at the beginning of the index task
+ // and change updates that happen after this read will not be considered when updating the
+ // index.
+ // * Trying to remove the IndexTask from queuedIndexTasks at the beginning of the task doesn't
+ // work if the computeIfAbsent method hasn't finished yet. Either the queuedIndexTasks doesn't
+ // contain the new entry yet and the removal has no effect as it is done before the entry is
+ // added to the map, or the removal fails with {@link IllegalStateException} as recursive
+ // updates from within the computeIfAbsent callback are not allowed.
+ return task.submitIfNeeded();
}
/**
@@ -155,8 +183,9 @@
* @param ids changes to index.
* @return future for completing indexing of all changes.
*/
- public ListenableFuture<?> indexAsync(Project.NameKey project, Collection<Change.Id> ids) {
- List<ListenableFuture<?>> futures = new ArrayList<>(ids.size());
+ public ListenableFuture<List<ChangeData>> indexAsync(
+ Project.NameKey project, Collection<Change.Id> ids) {
+ List<ListenableFuture<ChangeData>> futures = new ArrayList<>(ids.size());
for (Change.Id id : ids) {
futures.add(indexAsync(project, id));
}
@@ -259,9 +288,9 @@
* Start deleting a change.
*
* @param id change to delete.
- * @return future for the deleting task.
+ * @return future for the deleting task, the result of the future is always {@code null}
*/
- public ListenableFuture<?> deleteAsync(Change.Id id) {
+ public ListenableFuture<ChangeData> deleteAsync(Change.Id id) {
fireChangeScheduledForDeletionFromIndexEvent(id.get());
return submit(new DeleteTask(id));
}
@@ -359,17 +388,46 @@
}
}
- private class IndexTask extends AbstractIndexTask<Void> {
+ private class IndexTask extends AbstractIndexTask<ChangeData> {
+ ListenableFuture<ChangeData> future;
+
private IndexTask(Project.NameKey project, Change.Id id) {
super(project, id);
}
+ /**
+ * Submits this task to be executed, if it wasn't submitted yet.
+ *
+ * <p>Submits this task to the executor if it hasn't been submitted yet. The future is cached so
+ * that it can be returned if this method is called again.
+ *
+ * <p>This method must be synchronized so that concurrent calls do not submit this task to the
+ * executor multiple times.
+ *
+ * @return future from which the result of the index task (the {@link ChangeData} instance) can
+ * be retrieved.
+ */
+ private synchronized ListenableFuture<ChangeData> submitIfNeeded() {
+ if (future == null) {
+ future = submit(this);
+ }
+ return future;
+ }
+
@Override
- public Void callImpl() throws Exception {
+ public ChangeData callImpl() throws Exception {
+ // Remove this task from queuedIndexTasks. This is done right at the beginning of this task so
+ // that index requests which are received for the same change while this index task is in
+ // progress, are not dropped but added to the queue. This is important since change updates
+ // that happen after reading the change notes below will not be considered when updating the
+ // index.
remove();
+
try {
ChangeNotes changeNotes = notesFactory.createChecked(project, id);
- doIndex(changeDataFactory.create(changeNotes));
+ ChangeData changeData = changeDataFactory.create(changeNotes);
+ doIndex(changeData);
+ return changeData;
} catch (NoSuchChangeException e) {
doDelete(id);
}
@@ -397,12 +455,12 @@
@Override
protected void remove() {
- queuedIndexTasks.remove(this);
+ queuedIndexTasks.remove(id);
}
}
// Not AbstractIndexTask as it doesn't need a request context.
- private class DeleteTask implements Callable<Void> {
+ private class DeleteTask implements Callable<ChangeData> {
private final Change.Id id;
private DeleteTask(Change.Id id) {
@@ -410,7 +468,7 @@
}
@Override
- public Void call() {
+ public ChangeData call() {
logger.atFine().log("Delete change %d from index.", id.get());
// Don't bother setting a RequestContext to provide the DB.
// Implementations should not need to access the DB in order to delete a
diff --git a/java/com/google/gerrit/server/index/group/AllGroupsIndexer.java b/java/com/google/gerrit/server/index/group/AllGroupsIndexer.java
index 2d77f61..b3ef679 100644
--- a/java/com/google/gerrit/server/index/group/AllGroupsIndexer.java
+++ b/java/com/google/gerrit/server/index/group/AllGroupsIndexer.java
@@ -24,9 +24,9 @@
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.SiteIndexer;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.group.db.GroupsNoteDbConsistencyChecker;
import com.google.gerrit.server.index.IndexExecutor;
@@ -35,7 +35,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -88,16 +88,17 @@
AtomicInteger done = new AtomicInteger();
AtomicInteger failed = new AtomicInteger();
Stopwatch sw = Stopwatch.createStarted();
+ groupCache.evict(uuids);
+ Map<AccountGroup.UUID, InternalGroup> reindexedGroups = groupCache.get(uuids);
for (AccountGroup.UUID uuid : uuids) {
String desc = "group " + uuid;
ListenableFuture<?> future =
executor.submit(
() -> {
try {
- groupCache.evict(uuid);
- Optional<InternalGroup> internalGroup = groupCache.get(uuid);
- if (internalGroup.isPresent()) {
- index.replace(internalGroup.get());
+ InternalGroup internalGroup = reindexedGroups.get(uuid);
+ if (internalGroup != null) {
+ index.replace(internalGroup);
} else {
index.delete(uuid);
diff --git a/java/com/google/gerrit/server/index/group/GroupField.java b/java/com/google/gerrit/server/index/group/GroupField.java
index a3d913d..df90c0d 100644
--- a/java/com/google/gerrit/server/index/group/GroupField.java
+++ b/java/com/google/gerrit/server/index/group/GroupField.java
@@ -25,10 +25,10 @@
import com.google.common.base.MoreObjects;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.git.ObjectIds;
import com.google.gerrit.index.FieldDef;
import com.google.gerrit.index.SchemaUtil;
-import com.google.gerrit.server.group.InternalGroup;
import java.sql.Timestamp;
import org.eclipse.jgit.lib.ObjectId;
diff --git a/java/com/google/gerrit/server/index/group/GroupIndex.java b/java/com/google/gerrit/server/index/group/GroupIndex.java
index be569df..28c0384 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndex.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndex.java
@@ -15,10 +15,10 @@
package com.google.gerrit.server.index.group;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.Index;
import com.google.gerrit.index.IndexDefinition;
import com.google.gerrit.index.query.Predicate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.query.group.GroupPredicates;
/**
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexCollection.java b/java/com/google/gerrit/server/index/group/GroupIndexCollection.java
index 6c36a97..e1941ab 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexCollection.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexCollection.java
@@ -16,8 +16,8 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.IndexCollection;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Singleton;
/** Collection of active group indices. See {@link IndexCollection} for details on collections. */
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexDefinition.java b/java/com/google/gerrit/server/index/group/GroupIndexDefinition.java
index a9cd856..7b7d2e2 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexDefinition.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexDefinition.java
@@ -16,8 +16,8 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.IndexDefinition;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
/** Bundle of service classes that make up the group index. */
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexRewriter.java b/java/com/google/gerrit/server/index/group/GroupIndexRewriter.java
index a7b9497..86050bf 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexRewriter.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexRewriter.java
@@ -16,11 +16,11 @@
import static java.util.Objects.requireNonNull;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.IndexRewriter;
import com.google.gerrit.index.QueryOptions;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
index e9897e8..51e679f 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
@@ -18,11 +18,11 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.events.GroupIndexedListener;
import com.google.gerrit.index.Index;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.StalenessCheckResult;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
diff --git a/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java b/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
index 40e0d8e..c4d8952 100644
--- a/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
@@ -16,9 +16,9 @@
import static com.google.gerrit.index.SchemaUtil.schema;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.Schema;
import com.google.gerrit.index.SchemaDefinitions;
-import com.google.gerrit.server.group.InternalGroup;
/** Definition of group index versions (schemata). See {@link SchemaDefinitions}. */
public class GroupSchemaDefinitions extends SchemaDefinitions<InternalGroup> {
diff --git a/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java b/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
index 319b834..90070b6 100644
--- a/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
+++ b/java/com/google/gerrit/server/index/group/IndexedGroupQuery.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.index.group;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.Index;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.QueryOptions;
@@ -22,7 +23,6 @@
import com.google.gerrit.index.query.IndexedQuery;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
-import com.google.gerrit.server.group.InternalGroup;
import java.util.HashSet;
import java.util.Set;
diff --git a/java/com/google/gerrit/server/logging/LoggingContext.java b/java/com/google/gerrit/server/logging/LoggingContext.java
index a1b807d..5611d08 100644
--- a/java/com/google/gerrit/server/logging/LoggingContext.java
+++ b/java/com/google/gerrit/server/logging/LoggingContext.java
@@ -90,7 +90,6 @@
return tags.get() == null
&& forceLogging.get() == null
&& performanceLogging.get() == null
- && performanceLogRecords.get() == null
&& aclLogging.get() == null
&& aclLogRecords.get() == null;
}
@@ -181,16 +180,13 @@
* requests).
*
* @param enable whether performance logging should be enabled.
- * @return whether performance logging was be enabled before invoking this method (old value).
*/
- boolean performanceLogging(boolean enable) {
- Boolean oldValue = performanceLogging.get();
+ void performanceLogging(boolean enable) {
if (enable) {
performanceLogging.set(true);
} else {
performanceLogging.remove();
}
- return oldValue != null ? oldValue : false;
}
/**
@@ -307,10 +303,6 @@
return ImmutableList.of();
}
- void clearAclLogEntries() {
- aclLogRecords.remove();
- }
-
/**
* Set the ACL log records in this logging context. Existing log records are overwritten.
*
diff --git a/java/com/google/gerrit/server/logging/Metadata.java b/java/com/google/gerrit/server/logging/Metadata.java
index 1a4a335..71ee01f 100644
--- a/java/com/google/gerrit/server/logging/Metadata.java
+++ b/java/com/google/gerrit/server/logging/Metadata.java
@@ -103,6 +103,9 @@
public abstract Optional<Integer> indexVersion();
/** The name of the implementation method. */
+ public abstract Optional<String> memoryPoolName();
+
+ /** The name of the implementation method. */
public abstract Optional<String> methodName();
/** One or more resources */
@@ -309,6 +312,8 @@
public abstract Builder indexVersion(int indexVersion);
+ public abstract Builder memoryPoolName(@Nullable String memoryPoolName);
+
public abstract Builder methodName(@Nullable String methodName);
public abstract Builder multiple(boolean multiple);
diff --git a/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index df38118..af7f1b0 100644
--- a/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -65,7 +65,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.ManualRequestContext;
@@ -352,7 +352,7 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
String patchSetComment = null;
if (parsedComments.get(0).getType() == MailComment.CommentType.CHANGE_MESSAGE) {
patchSetComment = parsedComments.get(0).getMessage();
@@ -379,7 +379,7 @@
// Fire Gerrit event. Note that approvals can't be granted via email, so old and new approvals
// are always the same here.
commentAdded.fire(
- notes.getChange(),
+ ctx.getChangeData(notes),
patchSet,
ctx.getAccount(),
changeMessage.getMessage(),
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index 44453d5..f5fb6b0 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -56,7 +56,7 @@
/** Sends an email to one or more interested parties. */
public abstract class OutgoingEmail {
- private static final String SOY_TEMPLATE_NAMESPACE = "com.google.gerrit.server.mail.template.";
+ private static final String SOY_TEMPLATE_NAMESPACE = "com.google.gerrit.server.mail.template";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
protected String messageClass;
@@ -583,10 +583,22 @@
/** Configures a soy renderer for the given template name and rendering data map. */
private SoySauce.Renderer configureRenderer(String templateName) {
- return args.soySauce
- .get()
- .renderTemplate(SOY_TEMPLATE_NAMESPACE + templateName)
- .setData(soyContext);
+ int baseNameIndex = templateName.indexOf("_");
+ // In case there are multiple templates in file (now only InboundEmailRejection and
+ // InboundEmailRejectionHtml).
+ String fileNamespace =
+ baseNameIndex == -1 ? templateName : templateName.substring(0, baseNameIndex);
+ String templateInFileNamespace =
+ String.join(".", SOY_TEMPLATE_NAMESPACE, fileNamespace, templateName);
+ String templateInCommonNamespace = String.join(".", SOY_TEMPLATE_NAMESPACE, templateName);
+ SoySauce soySauce = args.soySauce.get();
+ // For backwards compatibility with existing customizations and plugin templates with the
+ // old non-unique namespace.
+ String fullTemplateName =
+ soySauce.hasTemplate(templateInFileNamespace)
+ ? templateInFileNamespace
+ : templateInCommonNamespace;
+ return soySauce.renderTemplate(fullTemplateName).setData(soyContext);
}
protected void removeUser(Account user) {
diff --git a/java/com/google/gerrit/server/notedb/MissingMetaObjectException.java b/java/com/google/gerrit/server/notedb/MissingMetaObjectException.java
index ffe9fa8..7f9de0d 100644
--- a/java/com/google/gerrit/server/notedb/MissingMetaObjectException.java
+++ b/java/com/google/gerrit/server/notedb/MissingMetaObjectException.java
@@ -16,6 +16,8 @@
/** Separate exception type to throw if requested meta SHA1 is not available. */
public class MissingMetaObjectException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
MissingMetaObjectException(String msg) {
super(msg);
}
diff --git a/java/com/google/gerrit/server/patch/AutoMerger.java b/java/com/google/gerrit/server/patch/AutoMerger.java
index ac37411..b99e2d2 100644
--- a/java/com/google/gerrit/server/patch/AutoMerger.java
+++ b/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -16,19 +16,23 @@
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Throwables;
-import com.google.gerrit.common.Nullable;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.UsedAt;
import com.google.gerrit.entities.RefNames;
-import com.google.gerrit.git.LockFailureException;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer1;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.InMemoryInserter;
import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.update.RetryHelper;
-import com.google.gerrit.server.update.RetryableAction.ActionType;
+import com.google.gerrit.server.logging.Metadata;
+import com.google.gerrit.server.update.RepoView;
import com.google.inject.Inject;
import java.io.IOException;
+import java.util.Optional;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
@@ -37,13 +41,13 @@
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.merge.ResolveMerger;
import org.eclipse.jgit.merge.ThreeWayMergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
/**
* Utility class for creating an auto-merge commit of a merge commit.
@@ -67,6 +71,8 @@
* is that these refs should never be deleted.
*/
public class AutoMerger {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
public static final String AUTO_MERGE_MSG_PREFIX = "Auto-merge of ";
@UsedAt(UsedAt.Project.GOOGLE)
@@ -74,92 +80,126 @@
return cfg.getBoolean("change", null, "cacheAutomerge", true);
}
- private final RetryHelper retryHelper;
+ private enum OperationType {
+ CACHE_LOAD,
+ IN_MEMORY_WRITE,
+ ON_DISK_WRITE
+ }
+
+ private final Counter1<OperationType> counter;
+ private final Timer1<OperationType> latency;
private final PersonIdent gerritIdent;
private final boolean save;
+ private final ThreeWayMergeStrategy configuredMergeStrategy;
@Inject
AutoMerger(
- RetryHelper retryHelper,
+ MetricMaker metricMaker,
@GerritServerConfig Config cfg,
@GerritPersonIdent PersonIdent gerritIdent) {
- this.retryHelper = retryHelper;
- save = cacheAutomerge(cfg);
+ this.counter =
+ metricMaker.newCounter(
+ "git/auto-merge/num_operations",
+ new Description("AutoMerge computations").setRate().setUnit("auto merge computations"),
+ Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName).build());
+ this.latency =
+ metricMaker.newTimer(
+ "git/auto-merge/latency",
+ new Description("AutoMerge computation latency")
+ .setCumulative()
+ .setUnit("milliseconds"),
+ Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName).build());
+ this.save = cacheAutomerge(cfg);
this.gerritIdent = gerritIdent;
+ this.configuredMergeStrategy = MergeUtil.getMergeStrategy(cfg);
}
/**
- * Creates an auto-merge commit of the parents of the given merge commit.
+ * Reads or creates an auto-merge commit of the parents of the given merge commit.
*
- * <p>In case of an exception the creation of the auto-merge commit is retried a few times. E.g.
- * this allows the operation to succeed if a Git update fails due to a temporary issue.
+ * <p>The result is read from Git or computed in-memory and not written back to Git. This method
+ * exists for backwards compatibility only. All new changes have their auto-merge commits written
+ * transactionally when the change or patch set is created.
*
* @return auto-merge commit. Headers of the returned RevCommit are parsed.
*/
- public RevCommit merge(
+ public RevCommit lookupFromGitOrMergeInMemory(
Repository repo,
RevWalk rw,
- ObjectInserter ins,
- RevCommit merge,
- ThreeWayMergeStrategy mergeStrategy)
- throws IOException {
- try {
- return retryHelper
- .action(
- ActionType.GIT_UPDATE,
- "createAutoMerge",
- () -> createAutoMergeCommit(repo, rw, ins, merge, mergeStrategy))
- .defaultTimeoutMultiplier(2)
- .call();
- } catch (Exception e) {
- Throwables.throwIfUnchecked(e);
- Throwables.throwIfInstanceOf(e, IOException.class);
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Creates an auto-merge commit of the parents of the given merge commit.
- *
- * @return auto-merge commit. Headers of the returned RevCommit are parsed.
- */
- private RevCommit createAutoMergeCommit(
- Repository repo,
- RevWalk rw,
- ObjectInserter ins,
+ InMemoryInserter ins,
RevCommit merge,
ThreeWayMergeStrategy mergeStrategy)
throws IOException {
checkArgument(rw.getObjectReader().getCreatedFromInserter() == ins);
+ Optional<RevCommit> existingCommit =
+ lookupCommit(repo, rw, RefNames.refsCacheAutomerge(merge.name()));
+ if (existingCommit.isPresent()) {
+ counter.increment(OperationType.CACHE_LOAD);
+ return existingCommit.get();
+ }
+ counter.increment(OperationType.IN_MEMORY_WRITE);
+ logger.atInfo().log("Computing in-memory AutoMerge for " + merge.name());
+ try (Timer1.Context ignored = latency.start(OperationType.IN_MEMORY_WRITE)) {
+ return rw.parseCommit(createAutoMergeCommit(repo.getConfig(), rw, ins, merge, mergeStrategy));
+ }
+ }
- InMemoryInserter tmpIns = null;
- if (ins instanceof InMemoryInserter) {
- // Caller gave us an in-memory inserter, so ensure anything we write from
- // this method is visible to them.
- tmpIns = (InMemoryInserter) ins;
- } else if (!save) {
- // If we don't plan on saving results, use a fully in-memory inserter.
- // Using just a non-flushing wrapper is not sufficient, since in
- // particular DfsInserter might try to write to storage after exceeding an
- // internal buffer size.
- tmpIns = new InMemoryInserter(rw.getObjectReader());
+ /**
+ * Creates an auto merge commit for the provided commit in case it is a merge commit. To be used
+ * whenever Gerrit creates new patch sets.
+ *
+ * <p>Callers need to include the returned {@link ReceiveCommand} in their ref transaction.
+ *
+ * @return A {@link ReceiveCommand} wrapped in an {@link Optional} to be used in a {@link
+ * org.eclipse.jgit.lib.BatchRefUpdate}. {@link Optional#empty()} in case we don't need an
+ * auto merge commit.
+ */
+ public Optional<ReceiveCommand> createAutoMergeCommitIfNecessary(
+ RepoView repoView, RevWalk rw, ObjectInserter ins, RevCommit maybeMergeCommit)
+ throws IOException {
+ if (maybeMergeCommit.getParentCount() != 2 || !save) {
+ logger.atFine().log("AutoMerge not required");
+ return Optional.empty();
}
+ if (repoView.getRef(RefNames.refsCacheAutomerge(maybeMergeCommit.name())).isPresent()) {
+ logger.atFine().log("AutoMerge alredy exists");
+ return Optional.empty();
+ }
+
+ ObjectId autoMerge;
+ try (Timer1.Context ignored = latency.start(OperationType.ON_DISK_WRITE)) {
+ autoMerge =
+ createAutoMergeCommit(
+ repoView.getConfig(), rw, ins, maybeMergeCommit, configuredMergeStrategy);
+ }
+ counter.increment(OperationType.ON_DISK_WRITE);
+ logger.atFine().log("Added %s AutoMerge ref update for commit", autoMerge.name());
+ return Optional.of(
+ new ReceiveCommand(
+ ObjectId.zeroId(), autoMerge, RefNames.refsCacheAutomerge(maybeMergeCommit.name())));
+ }
+
+ /**
+ * Creates an auto-merge commit of the parents of the given merge commit.
+ *
+ * @return auto-merge commit. Headers of the returned RevCommit are parsed.
+ */
+ private ObjectId createAutoMergeCommit(
+ Config repoConfig,
+ RevWalk rw,
+ ObjectInserter ins,
+ RevCommit merge,
+ ThreeWayMergeStrategy mergeStrategy)
+ throws IOException {
rw.parseHeaders(merge);
- String refName = RefNames.refsCacheAutomerge(merge.name());
- Ref ref = repo.getRefDatabase().exactRef(refName);
- if (ref != null && ref.getObjectId() != null) {
- RevObject obj = rw.parseAny(ref.getObjectId());
- if (obj instanceof RevCommit) {
- return (RevCommit) obj;
- }
- return commit(repo, rw, tmpIns, ins, refName, obj, merge);
- }
-
- ResolveMerger m = (ResolveMerger) mergeStrategy.newMerger(repo, true);
+ ResolveMerger m = (ResolveMerger) mergeStrategy.newMerger(ins, repoConfig);
DirCache dc = DirCache.newInCore();
m.setDirCache(dc);
- m.setObjectInserter(tmpIns == null ? new NonFlushingWrapper(ins) : tmpIns);
+ // If we don't plan on saving results, use a fully in-memory inserter.
+ // Using just a non-flushing wrapper is not sufficient, since in particular DfsInserter might
+ // try to write to storage after exceeding an internal buffer size.
+ m.setObjectInserter(ins instanceof InMemoryInserter ? new NonFlushingWrapper(ins) : ins);
boolean couldMerge = m.merge(merge.getParents());
@@ -179,18 +219,6 @@
m.getMergeResults());
}
- return commit(repo, rw, tmpIns, ins, refName, treeId, merge);
- }
-
- private RevCommit commit(
- Repository repo,
- RevWalk rw,
- @Nullable InMemoryInserter tmpIns,
- ObjectInserter ins,
- String refName,
- ObjectId tree,
- RevCommit merge)
- throws IOException {
rw.parseHeaders(merge);
// For maximum stability, choose a single ident using the committer time of
// the input commit, using the server name and timezone.
@@ -200,50 +228,34 @@
CommitBuilder cb = new CommitBuilder();
cb.setAuthor(ident);
cb.setCommitter(ident);
- cb.setTreeId(tree);
+ cb.setTreeId(treeId);
cb.setMessage(AUTO_MERGE_MSG_PREFIX + merge.name() + '\n');
for (RevCommit p : merge.getParents()) {
cb.addParentId(p);
}
- if (!save) {
- checkArgument(tmpIns != null);
- try (ObjectReader tmpReader = tmpIns.newReader();
+ if (ins instanceof InMemoryInserter) {
+ // When using an InMemoryInserter we need to read back the values from that inserter because
+ // they are not available.
+ try (ObjectReader tmpReader = ins.newReader();
RevWalk tmpRw = new RevWalk(tmpReader)) {
- return tmpRw.parseCommit(tmpIns.insert(cb));
+ return tmpRw.parseCommit(ins.insert(cb));
}
}
- checkArgument(tmpIns == null);
- checkArgument(!(ins instanceof InMemoryInserter));
- ObjectId commitId = ins.insert(cb);
- ins.flush();
+ return rw.parseCommit(ins.insert(cb));
+ }
- RefUpdate ru = repo.updateRef(refName);
- ru.setNewObjectId(commitId);
- ru.disableRefLog();
- switch (ru.forceUpdate()) {
- case FAST_FORWARD:
- case FORCED:
- case NEW:
- case NO_CHANGE:
- return rw.parseCommit(commitId);
- case LOCK_FAILURE:
- throw new LockFailureException(
- String.format("Failed to create auto-merge of %s", merge.name()), ru);
- case IO_FAILURE:
- case NOT_ATTEMPTED:
- case REJECTED:
- case REJECTED_CURRENT_BRANCH:
- case REJECTED_MISSING_OBJECT:
- case REJECTED_OTHER_REASON:
- case RENAMED:
- default:
- throw new IOException(
- String.format(
- "Failed to create auto-merge of %s: Cannot write %s (%s)",
- merge.name(), refName, ru.getResult()));
+ private Optional<RevCommit> lookupCommit(Repository repo, RevWalk rw, String refName)
+ throws IOException {
+ Ref ref = repo.getRefDatabase().exactRef(refName);
+ if (ref != null && ref.getObjectId() != null) {
+ RevObject obj = rw.parseAny(ref.getObjectId());
+ if (obj instanceof RevCommit) {
+ return Optional.of((RevCommit) obj);
+ }
}
+ return Optional.empty();
}
private static class NonFlushingWrapper extends ObjectInserter.Filter {
diff --git a/java/com/google/gerrit/server/patch/BaseCommitUtil.java b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
index de4a10e..7c06a62 100644
--- a/java/com/google/gerrit/server/patch/BaseCommitUtil.java
+++ b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
@@ -37,16 +37,11 @@
class BaseCommitUtil {
private final AutoMerger autoMerger;
private final ThreeWayMergeStrategy mergeStrategy;
-
- /** If true, auto-merge results are stored in the repository. */
- private final boolean saveAutomerge;
-
private final GitRepositoryManager repoManager;
@Inject
BaseCommitUtil(AutoMerger am, @GerritServerConfig Config cfg, GitRepositoryManager repoManager) {
this.autoMerger = am;
- this.saveAutomerge = AutoMerger.cacheAutomerge(cfg);
this.mergeStrategy = MergeUtil.getMergeStrategy(cfg);
this.repoManager = repoManager;
}
@@ -54,7 +49,7 @@
RevObject getBaseCommit(Project.NameKey project, ObjectId newCommit, @Nullable Integer parentNum)
throws IOException {
try (Repository repo = repoManager.openRepository(project);
- ObjectInserter ins = newInserter(repo);
+ InMemoryInserter ins = new InMemoryInserter(repo);
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
return getParentCommit(repo, ins, rw, parentNum, newCommit);
@@ -93,7 +88,7 @@
*/
RevObject getParentCommit(
Repository repo,
- ObjectInserter ins,
+ InMemoryInserter ins,
RevWalk rw,
@Nullable Integer parentNum,
ObjectId commitId)
@@ -112,16 +107,12 @@
}
// Only support auto-merge for 2 parents, not octopus merges
if (current.getParentCount() == 2) {
- return autoMerger.merge(repo, rw, ins, current, mergeStrategy);
+ return autoMerger.lookupFromGitOrMergeInMemory(repo, rw, ins, current, mergeStrategy);
}
return null;
}
}
- private ObjectInserter newInserter(Repository repo) {
- return saveAutomerge ? repo.newObjectInserter() : new InMemoryInserter(repo);
- }
-
private static ObjectId emptyTree(ObjectInserter ins) throws IOException {
ObjectId id = ins.insert(Constants.OBJ_TREE, new byte[] {});
ins.flush();
diff --git a/java/com/google/gerrit/server/patch/DiffOperations.java b/java/com/google/gerrit/server/patch/DiffOperations.java
index 93aefff..7213581 100644
--- a/java/com/google/gerrit/server/patch/DiffOperations.java
+++ b/java/com/google/gerrit/server/patch/DiffOperations.java
@@ -16,6 +16,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Patch;
+import com.google.gerrit.entities.Patch.ChangeType;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
@@ -47,7 +48,9 @@
* @param newCommit 20 bytes SHA-1 of the new commit used in the diff.
* @param parentNum integer specifying which parent to use as base. If null, the only parent will
* be used or the auto-merge if {@code newCommit} is a merge commit.
- * @return the list of modified files between the two commits.
+ * @return map of file paths to the file diffs. The map key is the new file path for all {@link
+ * ChangeType} file diffs except {@link ChangeType#DELETED} entries where the map key contains
+ * the old file path. The map entries are not sorted by key.
* @throws DiffNotAvailableException if auto-merge is requested for a commit having more than two
* parents, if the {@code newCommit} could not be parsed for extracting the base commit, or if
* an internal error occurred in Git while evaluating the diff.
@@ -63,7 +66,9 @@
* @param project a project name representing a git repository.
* @param oldCommit 20 bytes SHA-1 of the old commit used in the diff.
* @param newCommit 20 bytes SHA-1 of the new commit used in the diff.
- * @return the list of modified files between the two commits.
+ * @return map of file paths to the file diffs. The map key is the new file path for all {@link
+ * ChangeType} file diffs except {@link ChangeType#DELETED} entries where the map key contains
+ * the old file path. The map entries are not sorted by key.
* @throws DiffNotAvailableException if an internal error occurred in Git while evaluating the
* diff.
*/
diff --git a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
index efb64bc..6217239 100644
--- a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
+++ b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
@@ -28,6 +28,8 @@
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.patch.diff.ModifiedFilesCache;
import com.google.gerrit.server.patch.diff.ModifiedFilesCacheImpl;
import com.google.gerrit.server.patch.diff.ModifiedFilesCacheKey;
@@ -45,6 +47,12 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
/**
@@ -61,6 +69,8 @@
private final ModifiedFilesCache modifiedFilesCache;
private final FileDiffCache fileDiffCache;
private final BaseCommitUtil baseCommitUtil;
+ private final long timeoutMillis;
+ private final ExecutorService diffExecutor;
public static Module module() {
return new CacheModule() {
@@ -79,10 +89,21 @@
public DiffOperationsImpl(
ModifiedFilesCache modifiedFilesCache,
FileDiffCache fileDiffCache,
- BaseCommitUtil baseCommit) {
+ BaseCommitUtil baseCommit,
+ @DiffExecutor ExecutorService executor,
+ @GerritServerConfig Config cfg) {
this.modifiedFilesCache = modifiedFilesCache;
this.fileDiffCache = fileDiffCache;
this.baseCommitUtil = baseCommit;
+ this.diffExecutor = executor;
+ this.timeoutMillis =
+ ConfigUtil.getTimeUnit(
+ cfg,
+ "cache",
+ "diff",
+ "timeout",
+ TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS),
+ TimeUnit.MILLISECONDS);
}
@Override
@@ -91,7 +112,7 @@
throws DiffNotAvailableException {
try {
DiffParameters diffParams = computeDiffParameters(project, newCommit, parent);
- return getModifiedFiles(project, newCommit, diffParams);
+ return listModifiedFilesWithTimeout(diffParams);
} catch (IOException e) {
throw new DiffNotAvailableException(
"Failed to evaluate the parent/base commit for commit " + newCommit, e);
@@ -109,7 +130,7 @@
.baseCommit(oldCommit)
.comparisonType(ComparisonType.againstOtherPatchSet())
.build();
- return getModifiedFiles(project, newCommit, params);
+ return listModifiedFilesWithTimeout(params);
}
@Override
@@ -124,10 +145,7 @@
DiffParameters diffParams = computeDiffParameters(project, newCommit, parent);
FileDiffCacheKey key =
createFileDiffCacheKey(project, diffParams.baseCommit(), newCommit, fileName, whitespace);
- Map<String, FileDiffOutput> result = getModifiedFilesForKeys(ImmutableList.of(key));
- return result.containsKey(fileName)
- ? result.get(fileName)
- : FileDiffOutput.empty(fileName, key.oldCommit(), key.newCommit());
+ return getModifiedFileWithTimeout(key, diffParams);
} catch (IOException e) {
throw new DiffNotAvailableException(
"Failed to evaluate the parent/base commit for commit " + newCommit, e);
@@ -142,18 +160,67 @@
String fileName,
@Nullable DiffPreferencesInfo.Whitespace whitespace)
throws DiffNotAvailableException {
+ DiffParameters params = // used for logging only
+ DiffParameters.builder()
+ .project(project)
+ .baseCommit(oldCommit)
+ .newCommit(newCommit)
+ .comparisonType(ComparisonType.againstOtherPatchSet())
+ .build();
FileDiffCacheKey key =
createFileDiffCacheKey(project, oldCommit, newCommit, fileName, whitespace);
- Map<String, FileDiffOutput> result = getModifiedFilesForKeys(ImmutableList.of(key));
- return result.containsKey(fileName)
- ? result.get(fileName)
- : FileDiffOutput.empty(fileName, oldCommit, newCommit);
+ return getModifiedFileWithTimeout(key, params);
}
- private Map<String, FileDiffOutput> getModifiedFiles(
- Project.NameKey project, ObjectId newCommit, DiffParameters diffParams)
+ private Map<String, FileDiffOutput> listModifiedFilesWithTimeout(DiffParameters params)
+ throws DiffNotAvailableException {
+ Future<DiffResult> task =
+ diffExecutor.submit(
+ () -> {
+ ImmutableMap<String, FileDiffOutput> modifiedFiles = getModifiedFiles(params);
+ return DiffResult.create(null, modifiedFiles);
+ });
+ DiffResult diffResult = execDiffWithTimeout(task, params);
+ return diffResult.modifiedFiles();
+ }
+
+ private FileDiffOutput getModifiedFileWithTimeout(FileDiffCacheKey key, DiffParameters params)
+ throws DiffNotAvailableException {
+ Future<DiffResult> task =
+ diffExecutor.submit(
+ () -> {
+ Map<String, FileDiffOutput> diffList = getModifiedFilesForKeys(ImmutableList.of(key));
+ FileDiffOutput fileDiffOutput =
+ diffList.containsKey(key.newFilePath())
+ ? diffList.get(key.newFilePath())
+ : FileDiffOutput.empty(key.newFilePath(), key.oldCommit(), key.newCommit());
+ return DiffResult.create(fileDiffOutput, null);
+ });
+ DiffResult result = execDiffWithTimeout(task, params);
+ return result.fileDiff();
+ }
+
+ /** Executes a diff task by employing a timeout. */
+ private DiffResult execDiffWithTimeout(Future<DiffResult> task, DiffParameters params)
throws DiffNotAvailableException {
try {
+ return task.get(timeoutMillis, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | TimeoutException e) {
+ throw new DiffNotAvailableException(
+ String.format(
+ "Timeout reached while computing diff for project %s, old commit %s, new commit %s",
+ params.project(), params.baseCommit().name(), params.newCommit().name()),
+ e);
+ } catch (ExecutionException e) {
+ throw new DiffNotAvailableException(e);
+ }
+ }
+
+ private ImmutableMap<String, FileDiffOutput> getModifiedFiles(DiffParameters diffParams)
+ throws DiffNotAvailableException {
+ try {
+ Project.NameKey project = diffParams.project();
+ ObjectId newCommit = diffParams.newCommit();
ObjectId oldCommit = diffParams.baseCommit();
ComparisonType cmp = diffParams.comparisonType();
@@ -191,7 +258,7 @@
}
}
- private Map<String, FileDiffOutput> getModifiedFilesForKeys(List<FileDiffCacheKey> keys)
+ private ImmutableMap<String, FileDiffOutput> getModifiedFilesForKeys(List<FileDiffCacheKey> keys)
throws DiffNotAvailableException {
ImmutableMap.Builder<String, FileDiffOutput> files = ImmutableMap.builder();
ImmutableMap<FileDiffCacheKey, FileDiffOutput> fileDiffs = fileDiffCache.getAll(keys);
@@ -248,6 +315,26 @@
.build();
}
+ /**
+ * All interface methods create their results using this class. This is used so that the timeout
+ * method {@link #execDiffWithTimeout(Future, DiffParameters)} could be reused by all interface
+ * methods.
+ */
+ @AutoValue
+ abstract static class DiffResult {
+ static DiffResult create(
+ @Nullable FileDiffOutput fileDiff,
+ @Nullable ImmutableMap<String, FileDiffOutput> modifiedFiles) {
+ return new AutoValue_DiffOperationsImpl_DiffResult(fileDiff, modifiedFiles);
+ }
+
+ @Nullable
+ abstract FileDiffOutput fileDiff();
+
+ @Nullable
+ abstract ImmutableMap<String, FileDiffOutput> modifiedFiles();
+ }
+
@AutoValue
abstract static class DiffParameters {
abstract Project.NameKey project();
diff --git a/java/com/google/gerrit/server/patch/FilePathAdapter.java b/java/com/google/gerrit/server/patch/FilePathAdapter.java
new file mode 100644
index 0000000..7f34cf1
--- /dev/null
+++ b/java/com/google/gerrit/server/patch/FilePathAdapter.java
@@ -0,0 +1,52 @@
+package com.google.gerrit.server.patch;
+
+import com.google.gerrit.entities.Patch.ChangeType;
+import java.util.Optional;
+
+/**
+ * Adapter for old/new paths of the new diff cache to the old diff cache representation. This is
+ * needed for backward compatibility with all old diff cache callers.
+ *
+ * <p>TODO(ghareeb): It's better to revisit this logic and update all diff cache callers to use the
+ * new diff cache output directly.
+ */
+public class FilePathAdapter {
+ private FilePathAdapter() {}
+
+ /**
+ * Converts the old file path of the new diff cache output to the old diff cache representation.
+ */
+ public static String getOldPath(Optional<String> oldName, ChangeType changeType) {
+ switch (changeType) {
+ case DELETED:
+ case ADDED:
+ case MODIFIED:
+ case REWRITE:
+ return null;
+ case COPIED:
+ case RENAMED:
+ return oldName.get();
+ default:
+ throw new IllegalArgumentException("Unsupported type " + changeType);
+ }
+ }
+
+ /**
+ * Converts the new file path of the new diff cache output to the old diff cache representation.
+ */
+ public static String getNewPath(
+ Optional<String> oldName, Optional<String> newName, ChangeType changeType) {
+ switch (changeType) {
+ case DELETED:
+ return oldName.get();
+ case ADDED:
+ case MODIFIED:
+ case REWRITE:
+ case COPIED:
+ case RENAMED:
+ return newName.get();
+ default:
+ throw new IllegalArgumentException("Unsupported type " + changeType);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/patch/PatchListCache.java b/java/com/google/gerrit/server/patch/PatchListCache.java
index 63cac0e..e60302a 100644
--- a/java/com/google/gerrit/server/patch/PatchListCache.java
+++ b/java/com/google/gerrit/server/patch/PatchListCache.java
@@ -21,10 +21,38 @@
/** Provides a cached list of {@link PatchListEntry}. */
public interface PatchListCache {
+ /**
+ * Returns the patch list - list of modified files - between two commits.
+ *
+ * @param key identifies the old / new commits.
+ * @param project name key identifying a specific git project (repository).
+ * @return patch list containing the modified files between two commits.
+ * @deprecated use {@link DiffOperations} instead.
+ */
+ @Deprecated
PatchList get(PatchListKey key, Project.NameKey project) throws PatchListNotAvailableException;
+ /**
+ * Returns the patch list - list of modified files - between two commits.
+ *
+ * @param change entity containing all change data.
+ * @param patchSet single revision of a {@link Change}.
+ * @return patch list containing the modified files between two commits.
+ * @deprecated use {@link DiffOperations} instead.
+ */
+ @Deprecated
PatchList get(Change change, PatchSet patchSet) throws PatchListNotAvailableException;
+ /**
+ * Returns the patch list - list of modified files - between two commits.
+ *
+ * @param change entity containing all change data.
+ * @param patchSet single revision of a {@link Change}.
+ * @param parentNum 1-based parent number when new commit used in comparison is a merge commit.
+ * @return patch list containing the modified files between two commits.
+ * @deprecated use {@link DiffOperations} instead.
+ */
+ @Deprecated
ObjectId getOldId(Change change, PatchSet patchSet, Integer parentNum)
throws PatchListNotAvailableException;
diff --git a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index ae30113..5998bba 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -14,7 +14,8 @@
package com.google.gerrit.server.patch;
-import static java.nio.charset.StandardCharsets.UTF_8;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -31,6 +32,8 @@
import com.google.gerrit.server.mime.FileTypeRegistry;
import com.google.gerrit.server.patch.DiffContentCalculator.DiffCalculatorResult;
import com.google.gerrit.server.patch.DiffContentCalculator.TextSource;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
+import com.google.gerrit.server.patch.filediff.TaggedEdit;
import com.google.inject.Inject;
import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil2;
@@ -68,7 +71,8 @@
intralineDiffCalculator = calculator;
}
- PatchScript toPatchScript(Repository git, PatchList list, PatchListEntry content)
+ /** Convert into {@link PatchScript} using the old diff cache output. */
+ PatchScript toPatchScriptOld(Repository git, PatchList list, PatchListEntry content)
throws IOException {
PatchFileChange change =
@@ -87,6 +91,32 @@
return build(sides.a, sides.b, change);
}
+ /** Convert into {@link PatchScript} using the new diff cache output. */
+ PatchScript toPatchScriptNew(Repository git, FileDiffOutput content) throws IOException {
+ PatchFileChange change =
+ new PatchFileChange(
+ content.edits().stream().map(TaggedEdit::jgitEdit).collect(toImmutableList()),
+ content.edits().stream()
+ .filter(TaggedEdit::dueToRebase)
+ .map(TaggedEdit::jgitEdit)
+ .collect(toImmutableSet()),
+ content.headerLines(),
+ FilePathAdapter.getOldPath(content.oldPath(), content.changeType()),
+ FilePathAdapter.getNewPath(content.oldPath(), content.newPath(), content.changeType()),
+ content.changeType(),
+ content.patchType().orElse(null));
+ SidesResolver sidesResolver = new SidesResolver(git, content.comparisonType());
+ ResolvedSides sides =
+ resolveSides(
+ git,
+ sidesResolver,
+ oldName(change),
+ newName(change),
+ content.oldCommitId(),
+ content.newCommitId());
+ return build(sides.a, sides.b, change);
+ }
+
private ResolvedSides resolveSides(
Repository git,
SidesResolver sidesResolver,
@@ -352,16 +382,8 @@
byte[] srcContent;
if (reuse) {
srcContent = other.srcContent;
-
- } else if (mode.getObjectType() == Constants.OBJ_BLOB) {
- srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB));
-
- } else if (mode.getObjectType() == Constants.OBJ_COMMIT) {
- String strContent = "Subproject commit " + ObjectId.toString(id);
- srcContent = strContent.getBytes(UTF_8);
-
} else {
- srcContent = Text.NO_BYTES;
+ srcContent = SrcContentResolver.getSourceContent(db, id, mode);
}
String mimeType = MimeUtil2.UNKNOWN_MIME_TYPE.toString();
DisplayMethod displayMethod = DisplayMethod.DIFF;
diff --git a/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index 826198f..885459a 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -24,17 +24,25 @@
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LargeObjectException;
+import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchScriptBuilder.IntraLineDiffCalculatorResult;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -42,15 +50,23 @@
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.lang.exception.ExceptionUtils;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
@@ -77,10 +93,33 @@
CurrentUser currentUser);
}
+ /** These metrics are temporary for launching the new redesigned diff cache. */
+ @Singleton
+ static class Metrics {
+ final Counter1<String> diffs;
+ static final String MATCH = "match";
+ static final String MISMATCH = "mismatch";
+ static final String ERROR = "error";
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ diffs =
+ metricMaker.newCounter(
+ "diff/get_diff/dark_launch",
+ new Description(
+ "Total number of matching, non-matching, or error in diffs in the old and new diff cache implementations.")
+ .setRate()
+ .setUnit("count"),
+ Field.ofString("type", Metadata.Builder::eventType).build());
+ }
+ }
+
private final GitRepositoryManager repoManager;
private final PatchSetUtil psUtil;
private final Provider<PatchScriptBuilder> builderFactory;
private final PatchListCache patchListCache;
+ private final Metrics metrics;
+ private final ExecutorService executor;
private final String fileName;
@Nullable private final PatchSet.Id psa;
@@ -92,11 +131,14 @@
private final ChangeEditUtil editReader;
private final PermissionBackend permissionBackend;
private final ProjectCache projectCache;
+ private final DiffOperations diffOperations;
private final Change.Id changeId;
private ChangeNotes notes;
+ private final boolean runNewDiffCache;
+
@AssistedInject
PatchScriptFactory(
GitRepositoryManager grm,
@@ -106,6 +148,10 @@
ChangeEditUtil editReader,
PermissionBackend permissionBackend,
ProjectCache projectCache,
+ DiffOperations diffOperations,
+ Metrics metrics,
+ @DiffExecutor ExecutorService executor,
+ @GerritServerConfig Config cfg,
@Assisted ChangeNotes notes,
@Assisted String fileName,
@Assisted("patchSetA") @Nullable PatchSet.Id patchSetA,
@@ -120,6 +166,9 @@
this.editReader = editReader;
this.permissionBackend = permissionBackend;
this.projectCache = projectCache;
+ this.diffOperations = diffOperations;
+ this.metrics = metrics;
+ this.executor = executor;
this.fileName = fileName;
this.psa = patchSetA;
@@ -128,6 +177,8 @@
this.diffPrefs = diffPrefs;
this.currentUser = currentUser;
+ this.runNewDiffCache = cfg.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
+
changeId = patchSetB.changeId();
}
@@ -140,6 +191,10 @@
ChangeEditUtil editReader,
PermissionBackend permissionBackend,
ProjectCache projectCache,
+ DiffOperations diffOperations,
+ Metrics metrics,
+ @DiffExecutor ExecutorService executor,
+ @GerritServerConfig Config cfg,
@Assisted ChangeNotes notes,
@Assisted String fileName,
@Assisted int parentNum,
@@ -154,6 +209,9 @@
this.editReader = editReader;
this.permissionBackend = permissionBackend;
this.projectCache = projectCache;
+ this.diffOperations = diffOperations;
+ this.metrics = metrics;
+ this.executor = executor;
this.fileName = fileName;
this.psa = null;
@@ -162,6 +220,8 @@
this.diffPrefs = diffPrefs;
this.currentUser = currentUser;
+ this.runNewDiffCache = cfg.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
+
changeId = patchSetB.changeId();
checkArgument(parentNum >= 0, "parentNum must be >= 0");
}
@@ -199,14 +259,19 @@
}
bId = edit.get().getEditCommit();
}
-
- final PatchList list = listFor(keyFor(aId, bId, diffPrefs.ignoreWhitespace));
- final PatchScriptBuilder b = newBuilder();
- final PatchListEntry content = list.get(fileName);
-
- return b.toPatchScript(git, list, content);
+ if (runNewDiffCache) {
+ PatchScript patchScript = getPatchScriptWithNewDiffCache(git, aId, bId);
+ // TODO(ghareeb): remove the async run. This is temporarily used to keep sanity checking
+ // the results while rolling out the new diff cache.
+ runOldDiffCacheAsyncAndExportMetrics(git, aId, bId, patchScript);
+ return patchScript;
+ } else {
+ return getPatchScriptWithOldDiffCache(git, aId, bId);
+ }
} catch (PatchListNotAvailableException e) {
throw new NoSuchChangeException(changeId, e);
+ } catch (DiffNotAvailableException e) {
+ throw new StorageException(e);
} catch (IOException e) {
logger.atSevere().withCause(e).log("File content unavailable");
throw new NoSuchChangeException(changeId, e);
@@ -222,6 +287,111 @@
}
}
+ private void runOldDiffCacheAsyncAndExportMetrics(
+ Repository git, ObjectId aId, ObjectId bId, PatchScript expected) {
+ @SuppressWarnings("unused")
+ Future<?> possiblyIgnoredError =
+ executor.submit(
+ () -> {
+ try {
+ PatchScript patchScript = getPatchScriptWithOldDiffCache(git, aId, bId);
+ if (areEqualPatchscripts(patchScript, expected)) {
+ metrics.diffs.increment(Metrics.MATCH);
+ } else {
+ metrics.diffs.increment(Metrics.MISMATCH);
+ logger.atWarning().atMostEvery(10, TimeUnit.SECONDS).log(
+ "Mismatching diff for change %s, old commit ID: %s, new commit ID: %s, file name: %s.",
+ changeId.toString(), aId, bId, fileName);
+ }
+ } catch (PatchListNotAvailableException | IOException e) {
+ metrics.diffs.increment(Metrics.ERROR);
+ logger.atSevere().atMostEvery(10, TimeUnit.SECONDS).log(
+ String.format(
+ "Error computing new diff for change %s, old commit ID: %s, new commit ID: %s.\n",
+ changeId.toString(), aId, bId)
+ + ExceptionUtils.getStackTrace(e));
+ }
+ });
+ }
+
+ private PatchScript getPatchScriptWithOldDiffCache(Repository git, ObjectId aId, ObjectId bId)
+ throws IOException, PatchListNotAvailableException {
+ PatchScriptBuilder patchScriptBuilder = newBuilder();
+ PatchList list = listFor(keyFor(aId, bId, diffPrefs.ignoreWhitespace));
+ PatchListEntry content = list.get(fileName);
+ return patchScriptBuilder.toPatchScriptOld(git, list, content);
+ }
+
+ private PatchScript getPatchScriptWithNewDiffCache(Repository git, ObjectId aId, ObjectId bId)
+ throws IOException, DiffNotAvailableException {
+ FileDiffOutput fileDiffOutput =
+ aId == null
+ ? diffOperations.getModifiedFileAgainstParent(
+ notes.getProjectName(),
+ bId,
+ parentNum == -1 ? null : parentNum + 1,
+ fileName,
+ diffPrefs.ignoreWhitespace)
+ : diffOperations.getModifiedFile(
+ notes.getProjectName(), aId, bId, fileName, diffPrefs.ignoreWhitespace);
+ return newBuilder().toPatchScriptNew(git, fileDiffOutput);
+ }
+
+ /**
+ * The comparison is not exhaustive but is using the most important fields. Comparing all fields
+ * will require some work in {@link PatchScript} to, e.g., convert it to autovalue. This
+ * comparison method shall give a strong signal that both patchscripts are almost identical.
+ */
+ private static boolean areEqualPatchscripts(PatchScript ps1, PatchScript ps2) {
+ boolean equal = true;
+ if (!ps1.getChangeType().equals(ps2.getChangeType())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching change type: old = %s, new = %s.", ps1.getChangeType(), ps2.getChangeType());
+ }
+ if (!ps1.getPatchHeader().equals(ps2.getPatchHeader())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching patch header: old = %s, new = %s.",
+ ps1.getPatchHeader(), ps2.getPatchHeader());
+ }
+ if (!Objects.equals(ps1.getOldName(), ps2.getOldName())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching old name: old = %s, new = %s.", ps1.getOldName(), ps2.getOldName());
+ }
+ if (!Objects.equals(ps1.getNewName(), ps2.getNewName())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching new name: old = %s, new = %s.", ps1.getNewName(), ps2.getNewName());
+ }
+ if (!ps1.getEdits().containsAll(ps2.getEdits())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching edits: old = %s, new = %s.", ps1.getEdits(), ps2.getEdits());
+ }
+ if (!ps2.getEdits().containsAll(ps1.getEdits())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching edits: old = %s, new = %s.", ps1.getEdits(), ps2.getEdits());
+ }
+ if (!ps1.getEditsDueToRebase().equals(ps2.getEditsDueToRebase())) {
+ equal = false;
+ logger.atWarning().log(
+ "Mismatching edits due to rebase: old = %s, new = %s.",
+ ps1.getEditsDueToRebase(), ps2.getEditsDueToRebase());
+ }
+ if (!ps1.getA().equals(ps2.getA())) {
+ equal = false;
+ logger.atWarning().log("Mismatching sparse file content in old commit.");
+ }
+ if (!ps1.getB().equals(ps2.getB())) {
+ equal = false;
+ logger.atWarning().log("Mismatching sparse file content in new commit.");
+ }
+ return equal;
+ }
+
private Optional<ObjectId> getAId() {
if (psa == null) {
return Optional.empty();
diff --git a/java/com/google/gerrit/server/patch/SrcContentResolver.java b/java/com/google/gerrit/server/patch/SrcContentResolver.java
new file mode 100644
index 0000000..9cd11d2
--- /dev/null
+++ b/java/com/google/gerrit/server/patch/SrcContentResolver.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.patch;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.IOException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+
+/** Resolver of the source content of a specific file */
+public class SrcContentResolver {
+
+ private SrcContentResolver() {}
+
+ /**
+ * Return the source content of a specific file.
+ *
+ * @param repo Git repository.
+ * @param id Git Object ID of the file blob.
+ * @param fileMode File mode of the underlying file as recognized by Git.
+ * @return byte[] source content of the underlying file if the {@code id} is of type blob, or a
+ * textual representation of the file if it is a git submodule.
+ * @throws IOException the object ID does not exist in the repository or cannot be accessed.
+ */
+ public static byte[] getSourceContent(Repository repo, ObjectId id, FileMode fileMode)
+ throws IOException {
+ if (fileMode.getObjectType() == Constants.OBJ_BLOB) {
+ return Text.asByteArray(repo.open(id, Constants.OBJ_BLOB));
+ }
+ if (fileMode.getObjectType() == Constants.OBJ_COMMIT) {
+ String strContent = "Subproject commit " + ObjectId.toString(id);
+ return strContent.getBytes(UTF_8);
+ }
+ return Text.NO_BYTES;
+ }
+}
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
index 1bb407d..395312f 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
@@ -93,7 +93,7 @@
persist(DIFF, FileDiffCacheKey.class, FileDiffOutput.class)
.maximumWeight(10 << 20)
.weigher(FileDiffWeigher.class)
- .version(2)
+ .version(4)
.keySerializer(FileDiffCacheKey.Serializer.INSTANCE)
.valueSerializer(FileDiffOutput.Serializer.INSTANCE)
.loader(FileDiffLoader.class);
@@ -203,9 +203,8 @@
// COMMIT_MSG and MERGE_LIST evaluations outside of the diff cache. For more details, see
// discussion in
// https://gerrit-review.googlesource.com/c/gerrit/+/280519/6..18/java/com/google/gerrit/server/patch/FileDiffCache.java#b540
- Text oldCommitMsgTxt = Text.forCommit(reader, oldCommit);
- if (oldCommitMsgTxt.size() > 0
- && oldCommitMsgTxt.getString(0).startsWith(AutoMerger.AUTO_MERGE_MSG_PREFIX)) {
+ String oldCommitMsgTxt = new String(Text.forCommit(reader, oldCommit).getContent(), UTF_8);
+ if (oldCommitMsgTxt.contains(AutoMerger.AUTO_MERGE_MSG_PREFIX)) {
return ComparisonType.againstAutoMerge();
}
return ComparisonType.againstOtherPatchSet();
diff --git a/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java b/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
index 97b55dc..e2c1bc5 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileSizeEvaluator.java
@@ -90,6 +90,8 @@
}
private static boolean isBlob(Patch.FileMode mode) {
- return mode.equals(FileMode.REGULAR_FILE) || mode.equals(FileMode.SYMLINK);
+ return mode.equals(FileMode.REGULAR_FILE)
+ || mode.equals(FileMode.EXECUTABLE_FILE)
+ || mode.equals(FileMode.SYMLINK);
}
}
diff --git a/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java b/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
index d1c0b45..017e276 100644
--- a/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
+++ b/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
@@ -107,7 +107,6 @@
private final PatchListKey key;
private final Project.NameKey project;
private final long timeoutMillis;
- private final boolean save;
@Inject
PatchListLoader(
@@ -133,13 +132,12 @@
"timeout",
TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS),
TimeUnit.MILLISECONDS);
- save = AutoMerger.cacheAutomerge(cfg);
}
@Override
public PatchList call() throws IOException, PatchListNotAvailableException {
try (Repository repo = repoManager.openRepository(project);
- ObjectInserter ins = newInserter(repo);
+ InMemoryInserter ins = new InMemoryInserter(repo);
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
return readPatchList(repo, rw, ins);
@@ -163,11 +161,7 @@
}
}
- private ObjectInserter newInserter(Repository repo) {
- return save ? repo.newObjectInserter() : new InMemoryInserter(repo);
- }
-
- private PatchList readPatchList(Repository repo, RevWalk rw, ObjectInserter ins)
+ private PatchList readPatchList(Repository repo, RevWalk rw, InMemoryInserter ins)
throws IOException, PatchListNotAvailableException {
ObjectReader reader = rw.getObjectReader();
checkArgument(reader.getCreatedFromInserter() == ins);
@@ -634,7 +628,7 @@
}
private RevObject aFor(
- PatchListKey key, Repository repo, RevWalk rw, ObjectInserter ins, RevCommit b)
+ PatchListKey key, Repository repo, RevWalk rw, InMemoryInserter ins, RevCommit b)
throws IOException {
if (key.getOldId() != null) {
return rw.parseAny(key.getOldId());
@@ -657,7 +651,7 @@
}
// Only support auto-merge for 2 parents, not octopus merges
if (b.getParentCount() == 2) {
- return autoMerger.merge(repo, rw, ins, b, mergeStrategy);
+ return autoMerger.lookupFromGitOrMergeInMemory(repo, rw, ins, b, mergeStrategy);
}
return null;
}
diff --git a/java/com/google/gerrit/server/patch/filediff/TaggedEdit.java b/java/com/google/gerrit/server/patch/filediff/TaggedEdit.java
index aef2f63..3720680 100644
--- a/java/com/google/gerrit/server/patch/filediff/TaggedEdit.java
+++ b/java/com/google/gerrit/server/patch/filediff/TaggedEdit.java
@@ -27,7 +27,11 @@
return new AutoValue_TaggedEdit(edit, dueToRebase);
}
- abstract Edit edit();
+ public abstract Edit edit();
- abstract boolean dueToRebase();
+ public org.eclipse.jgit.diff.Edit jgitEdit() {
+ return Edit.toJGitEdit(edit());
+ }
+
+ public abstract boolean dueToRebase();
}
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
index a01d447..e1af81d 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
@@ -209,9 +209,6 @@
private static final FieldDescriptor NEW_MODE_DESCRIPTOR =
GitFileDiffProto.getDescriptor().findFieldByNumber(8);
- private static final FieldDescriptor CHANGE_TYPE_DESCRIPTOR =
- GitFileDiffProto.getDescriptor().findFieldByNumber(9);
-
private static final FieldDescriptor PATCH_TYPE_DESCRIPTOR =
GitFileDiffProto.getDescriptor().findFieldByNumber(10);
diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java b/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
index dcaf485..9d69d9b 100644
--- a/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
+++ b/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
@@ -55,12 +55,12 @@
.put(GlobalPermission.RUN_AS, GlobalCapability.RUN_AS)
.put(GlobalPermission.RUN_GC, GlobalCapability.RUN_GC)
.put(GlobalPermission.STREAM_EVENTS, GlobalCapability.STREAM_EVENTS)
+ .put(GlobalPermission.VIEW_ACCESS, GlobalCapability.VIEW_ACCESS)
.put(GlobalPermission.VIEW_ALL_ACCOUNTS, GlobalCapability.VIEW_ALL_ACCOUNTS)
.put(GlobalPermission.VIEW_CACHES, GlobalCapability.VIEW_CACHES)
.put(GlobalPermission.VIEW_CONNECTIONS, GlobalCapability.VIEW_CONNECTIONS)
.put(GlobalPermission.VIEW_PLUGINS, GlobalCapability.VIEW_PLUGINS)
.put(GlobalPermission.VIEW_QUEUE, GlobalCapability.VIEW_QUEUE)
- .put(GlobalPermission.VIEW_ACCESS, GlobalCapability.VIEW_ACCESS)
.build();
static {
diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
index 5092e12..10aa9cd 100644
--- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
+++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
@@ -148,11 +148,11 @@
// Perform an initial ref filtering with all the refs the caller asked for. If we find tags that
// we have to investigate separately (deferred tags) then perform a reachability check starting
// from all visible branches (refs/heads/*).
- Result initialRefFilter = filterRefs(new ArrayList<>(refs), repo, opts);
+ Result initialRefFilter = filterRefs(new ArrayList<>(refs), opts);
List<Ref> visibleRefs = initialRefFilter.visibleRefs();
if (!initialRefFilter.deferredTags().isEmpty()) {
try (TraceTimer traceTimer = TraceContext.newTimer("Check visibility of deferred tags")) {
- Result allVisibleBranches = filterRefs(getTaggableRefs(repo), repo, opts);
+ Result allVisibleBranches = filterRefs(getTaggableRefs(repo), opts);
checkState(
allVisibleBranches.deferredTags().isEmpty(),
"unexpected tags found when filtering refs/heads/* "
@@ -186,8 +186,7 @@
* separately for later rev-walk-based visibility computation. Tags where visibility is trivial to
* compute will be returned as part of {@link Result#visibleRefs()}.
*/
- Result filterRefs(List<Ref> refs, Repository repo, RefFilterOptions opts)
- throws PermissionBackendException {
+ Result filterRefs(List<Ref> refs, RefFilterOptions opts) throws PermissionBackendException {
logger.atFinest().log("Filter refs (refs = %s)", refs);
// TODO(hiesel): Remove when optimization is done.
diff --git a/java/com/google/gerrit/server/permissions/GlobalPermission.java b/java/com/google/gerrit/server/permissions/GlobalPermission.java
index d4f22e6..c0b44e5 100644
--- a/java/com/google/gerrit/server/permissions/GlobalPermission.java
+++ b/java/com/google/gerrit/server/permissions/GlobalPermission.java
@@ -53,12 +53,12 @@
RUN_AS,
RUN_GC,
STREAM_EVENTS,
+ VIEW_ACCESS,
VIEW_ALL_ACCOUNTS,
VIEW_CACHES,
VIEW_CONNECTIONS,
VIEW_PLUGINS,
- VIEW_QUEUE,
- VIEW_ACCESS;
+ VIEW_QUEUE;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/permissions/SectionSortCache.java b/java/com/google/gerrit/server/permissions/SectionSortCache.java
index 6081e9a..d800782 100644
--- a/java/com/google/gerrit/server/permissions/SectionSortCache.java
+++ b/java/com/google/gerrit/server/permissions/SectionSortCache.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.permissions;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
import com.google.auto.value.AutoValue;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
@@ -28,6 +30,8 @@
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
/**
* Caches the order AccessSections should be sorted for evaluation.
@@ -60,67 +64,62 @@
this.cache = cache;
}
- // Sorts the given sections, but does not disturb ordering between equally exact sections.
+ /**
+ * Sorts the given sections in-place, but does not disturb ordering between equally exact
+ * sections.
+ */
void sort(String ref, List<AccessSection> sections) {
final int cnt = sections.size();
if (cnt <= 1) {
return;
}
-
EntryKey key = EntryKey.create(ref, sections);
- EntryVal val = cache.getIfPresent(key);
- if (val != null) {
- int[] srcIdx = val.order;
- if (srcIdx != null) {
- AccessSection[] srcList = copy(sections);
- for (int i = 0; i < cnt; i++) {
- sections.set(i, srcList[srcIdx[i]]);
- }
- } else {
- // Identity transform. No sorting is required.
- }
+ EntryVal val;
+ try {
+ val = cache.get(key, new Loader(key, sections));
+ } catch (ExecutionException e) {
+ logger.atWarning().withCause(e).log("Error happened while sorting access sections.");
+ return;
+ }
+ ImmutableList<Integer> order = val.order();
+ List<AccessSection> sorted = new ArrayList<>();
+ for (int i = 0; i < cnt; i++) {
+ sorted.add(sections.get(order.get(i)));
+ }
+ for (int i = 0; i < cnt; i++) {
+ sections.set(i, sorted.get(i));
+ }
+ }
- } else {
- boolean poison = false;
+ private static class Loader implements Callable<EntryVal> {
+ private final List<AccessSection> sections;
+ EntryKey key;
+
+ Loader(EntryKey key, List<AccessSection> sections) {
+ this.key = key;
+ this.sections = sections;
+ }
+
+ @Override
+ public EntryVal call() throws Exception {
+ // We use IdentityHashMap (which uses reference equality for keys/values) to preserve distinct
+ // entries in the map for identical AccessSection keys
IdentityHashMap<AccessSection, Integer> srcMap = new IdentityHashMap<>();
- for (int i = 0; i < cnt; i++) {
- poison |= srcMap.put(sections.get(i), i) != null;
+ for (int i = 0; i < sections.size(); i++) {
+ srcMap.put(sections.get(i), i);
}
-
- sections.sort(new MostSpecificComparator(ref));
-
- int[] srcIdx;
- if (isIdentityTransform(sections, srcMap)) {
- srcIdx = null;
- } else {
- srcIdx = new int[cnt];
- for (int i = 0; i < cnt; i++) {
- srcIdx[i] = srcMap.get(sections.get(i));
- }
+ ImmutableList<AccessSection> sorted =
+ sections.stream()
+ .sorted(new MostSpecificComparator(key.ref()))
+ .collect(toImmutableList());
+ ImmutableList.Builder<Integer> order = ImmutableList.builderWithExpectedSize(sections.size());
+ for (int i = 0; i < sorted.size(); i++) {
+ order.add(srcMap.get(sorted.get(i)));
}
-
- if (poison) {
- logger.atSevere().log("Received duplicate AccessSection instances, not caching sort");
- } else {
- cache.put(key, new EntryVal(srcIdx));
- }
+ return EntryVal.create(order.build());
}
}
- private static AccessSection[] copy(List<AccessSection> sections) {
- return sections.toArray(new AccessSection[sections.size()]);
- }
-
- private static boolean isIdentityTransform(
- List<AccessSection> sections, IdentityHashMap<AccessSection, Integer> srcMap) {
- for (int i = 0; i < sections.size(); i++) {
- if (i != srcMap.get(sections.get(i))) {
- return false;
- }
- }
- return true;
- }
-
@AutoValue
abstract static class EntryKey {
public abstract String ref();
@@ -146,17 +145,18 @@
}
}
- static final class EntryVal {
+ @AutoValue
+ abstract static class EntryVal {
/**
* Maps the input index to the output index.
*
* <p>For {@code x == order[y]} the expression means move the item at source position {@code x}
* to the output position {@code y}.
*/
- final int[] order;
+ abstract ImmutableList<Integer> order();
- EntryVal(int[] order) {
- this.order = order;
+ static EntryVal create(ImmutableList<Integer> order) {
+ return new AutoValue_SectionSortCache_EntryVal(order);
}
}
}
diff --git a/java/com/google/gerrit/server/plugins/JsPlugin.java b/java/com/google/gerrit/server/plugins/JsPlugin.java
index 12028b60..c120cdd 100644
--- a/java/com/google/gerrit/server/plugins/JsPlugin.java
+++ b/java/com/google/gerrit/server/plugins/JsPlugin.java
@@ -40,8 +40,7 @@
String fileName = getSrcFile().getFileName().toString();
int firstDash = fileName.indexOf("-");
if (firstDash > 0) {
- int extension =
- fileName.endsWith(".js") ? fileName.lastIndexOf(".js") : fileName.lastIndexOf(".html");
+ int extension = fileName.lastIndexOf(".js");
if (extension > 0) {
return fileName.substring(firstDash + 1, extension);
}
diff --git a/java/com/google/gerrit/server/plugins/PluginLoader.java b/java/com/google/gerrit/server/plugins/PluginLoader.java
index c4f4a1f..0a06081 100644
--- a/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -733,7 +733,7 @@
}
private boolean isUiPlugin(String name) {
- return isPlugin(name, "js") || isPlugin(name, "html");
+ return isPlugin(name, "js");
}
private boolean isPlugin(String fileName, String ext) {
diff --git a/java/com/google/gerrit/server/project/ProjectLevelConfig.java b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
index d82a318..8256198 100644
--- a/java/com/google/gerrit/server/project/ProjectLevelConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
@@ -88,7 +88,7 @@
}
public Config getWithInheritance() {
- return getWithInheritance(false);
+ return getWithInheritance(/* merge= */ false);
}
/**
diff --git a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 0e50bb0..a7659d4 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -14,10 +14,10 @@
package com.google.gerrit.server.project;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.gerrit.server.project.ProjectCache.noSuchProject;
import com.google.common.collect.Streams;
-import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.entities.SubmitTypeRecord;
@@ -33,20 +33,14 @@
import com.google.gerrit.server.rules.SubmitRule;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* Evaluates a submit-like Prolog rule found in the rules.pl file of the current project and filters
* the results through rules found in the parent projects, all the way up to All-Projects.
*/
public class SubmitRuleEvaluator {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private static final String DEFAULT_MSG = "Error evaluating project rules, check server log";
-
private final ProjectCache projectCache;
private final PrologRule prologRule;
private final PluginSetContext<SubmitRule> submitRules;
@@ -85,21 +79,6 @@
this.opts = options;
}
- public static SubmitRecord defaultRuleError() {
- return createRuleError(DEFAULT_MSG);
- }
-
- public static SubmitRecord createRuleError(String err) {
- SubmitRecord rec = new SubmitRecord();
- rec.status = SubmitRecord.Status.RULE_ERROR;
- rec.errorMessage = err;
- return rec;
- }
-
- public static SubmitTypeRecord defaultTypeError() {
- return SubmitTypeRecord.error(DEFAULT_MSG);
- }
-
/**
* Evaluate the submit rules.
*
@@ -117,14 +96,22 @@
}
projectCache.get(cd.project()).orElseThrow(noSuchProject(cd.project()));
- } catch (StorageException | NoSuchProjectException e) {
- return Collections.singletonList(ruleError("Error looking up change " + cd.getId(), e));
+ } catch (NoSuchProjectException e) {
+ throw new IllegalStateException("Unable to find project while evaluating submit rule", e);
}
- if ((!opts.allowClosed() || OnlineReindexMode.isActive()) && change.isClosed()) {
- SubmitRecord rec = new SubmitRecord();
- rec.status = SubmitRecord.Status.CLOSED;
- return Collections.singletonList(rec);
+ if (change.isClosed() && (!opts.recomputeOnClosedChanges() || OnlineReindexMode.isActive())) {
+ return cd.notes().getSubmitRecords().stream()
+ .map(
+ r -> {
+ SubmitRecord record = r.deepCopy();
+ if (record.status == SubmitRecord.Status.OK) {
+ // Submit records that were OK when they got merged are CLOSED now.
+ record.status = SubmitRecord.Status.CLOSED;
+ }
+ return record;
+ })
+ .collect(toImmutableList());
}
// We evaluate all the plugin-defined evaluators,
@@ -133,15 +120,10 @@
.map(c -> c.call(s -> s.evaluate(cd)))
.filter(Optional::isPresent)
.map(Optional::get)
- .collect(Collectors.toList());
+ .collect(toImmutableList());
}
}
- private SubmitRecord ruleError(String err, Exception e) {
- logger.atSevere().withCause(e).log(err);
- return defaultRuleError();
- }
-
/**
* Evaluate the submit type rules to get the submit type.
*
@@ -153,15 +135,10 @@
try {
projectCache.get(cd.project()).orElseThrow(noSuchProject(cd.project()));
} catch (NoSuchProjectException e) {
- return typeError("Error looking up change " + cd.getId(), e);
+ throw new IllegalStateException("Unable to find project while evaluating submit rule", e);
}
return prologRule.getSubmitType(cd);
}
}
-
- private SubmitTypeRecord typeError(String err, Exception e) {
- logger.atSevere().withCause(e).log(err);
- return defaultTypeError();
- }
}
diff --git a/java/com/google/gerrit/server/project/SubmitRuleOptions.java b/java/com/google/gerrit/server/project/SubmitRuleOptions.java
index ad077c0..3b511e1 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleOptions.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleOptions.java
@@ -25,7 +25,7 @@
@AutoValue
public abstract class SubmitRuleOptions {
private static final SubmitRuleOptions defaults =
- new AutoValue_SubmitRuleOptions.Builder().allowClosed(false).build();
+ new AutoValue_SubmitRuleOptions.Builder().recomputeOnClosedChanges(false).build();
public static SubmitRuleOptions defaults() {
return defaults;
@@ -35,13 +35,16 @@
return defaults.toBuilder();
}
- public abstract boolean allowClosed();
+ /**
+ * True if the submit rules should be recomputed even when the change is already closed (merged).
+ */
+ public abstract boolean recomputeOnClosedChanges();
public abstract Builder toBuilder();
@AutoValue.Builder
public abstract static class Builder {
- public abstract SubmitRuleOptions.Builder allowClosed(boolean allowClosed);
+ public abstract SubmitRuleOptions.Builder recomputeOnClosedChanges(boolean allowClosed);
public abstract SubmitRuleOptions build();
}
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index bf56000..793e4ec 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -33,6 +33,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
+import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.UsedAt;
@@ -117,6 +118,23 @@
* lazyLoad=false disables loading from NoteDb, so we don't accidentally enable a slow path.
*/
public class ChangeData {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public enum StorageConstraint {
+ /**
+ * This instance was loaded from the change index. Backfilling missing data from NoteDb is not
+ * allowed.
+ */
+ INDEX_ONLY,
+ /**
+ * This instance was loaded from the change index. Backfilling missing data from NoteDb is
+ * allowed.
+ */
+ INDEX_PRIMARY_NOTEDB_SECONDARY,
+ /** This instance was loaded from NoteDb. */
+ NOTEDB_ONLY
+ }
+
public static List<Change> asChanges(List<ChangeData> changeDatas) {
List<Change> result = new ArrayList<>(changeDatas.size());
for (ChangeData cd : changeDatas) {
@@ -282,7 +300,7 @@
private final Map<SubmitRuleOptions, List<SubmitRecord>> submitRecords =
Maps.newLinkedHashMapWithExpectedSize(1);
- private boolean lazyLoad = true;
+ private StorageConstraint storageConstraint = StorageConstraint.NOTEDB_ONLY;
private Change change;
private ChangeNotes notes;
private String commitMessage;
@@ -300,7 +318,6 @@
private Optional<ChangedLines> changedLines;
private SubmitTypeRecord submitTypeRecord;
private Boolean mergeable;
- private Boolean merge;
private Set<String> hashtags;
private Map<Account.Id, Ref> editsByUser;
private Set<Account.Id> reviewedBy;
@@ -316,7 +333,7 @@
private PersonIdent author;
private PersonIdent committer;
private ImmutableSet<AttentionSetUpdate> attentionSet;
- private int parentCount;
+ private Integer parentCount;
private Integer unresolvedCommentCount;
private Integer totalCommentCount;
private LabelTypes labelTypes;
@@ -375,11 +392,17 @@
* lazyLoad} is on, the {@code ChangeData} object will load from the database ("lazily") when a
* field accessor is called.
*/
- public ChangeData setLazyLoad(boolean load) {
- lazyLoad = load;
+ public ChangeData setStorageConstraint(StorageConstraint storageConstraint) {
+ this.storageConstraint = storageConstraint;
return this;
}
+ /** Returns {@code true} if we allow reading data from NoteDb. */
+ public boolean lazyload() {
+ return storageConstraint.ordinal()
+ >= StorageConstraint.INDEX_PRIMARY_NOTEDB_SECONDARY.ordinal();
+ }
+
public AllUsersName getAllUsersNameForIndexing() {
return allUsersName;
}
@@ -394,7 +417,7 @@
public List<String> currentFilePaths() {
if (currentFiles == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
Optional<DiffSummary> p = getDiffSummary();
@@ -405,7 +428,7 @@
private Optional<DiffSummary> getDiffSummary() {
if (diffSummary == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Optional.empty();
}
@@ -436,7 +459,7 @@
public Optional<ChangedLines> changedLines() {
if (changedLines == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Optional.empty();
}
changedLines = computeChangedLines();
@@ -469,7 +492,7 @@
}
public Change change() {
- if (change == null && lazyLoad) {
+ if (change == null && lazyload()) {
reloadChange();
}
return change;
@@ -500,7 +523,7 @@
public ChangeNotes notes() {
if (notes == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
throw new StorageException("ChangeNotes not available, lazyLoad = false");
}
notes = notesFactory.create(project(), legacyId);
@@ -526,7 +549,7 @@
public List<PatchSetApproval> currentApprovals() {
if (currentApprovals == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
Change c = change();
@@ -607,7 +630,6 @@
author = c.getAuthorIdent();
committer = c.getCommitterIdent();
parentCount = c.getParentCount();
- merge = parentCount > 0;
} catch (IOException e) {
throw new StorageException(
String.format(
@@ -621,7 +643,7 @@
/** Returns the most recent update (i.e. status) per user. */
public ImmutableSet<AttentionSetUpdate> attentionSet() {
if (attentionSet == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableSet.of();
}
attentionSet = notes().getAttentionSet();
@@ -699,7 +721,7 @@
*/
public ListMultimap<PatchSet.Id, PatchSetApproval> approvals() {
if (allApprovals == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableListMultimap.of();
}
allApprovals = approvalsUtil.byChange(notes());
@@ -716,7 +738,7 @@
public ReviewerSet reviewers() {
if (reviewers == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
// 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");
@@ -732,7 +754,7 @@
public ReviewerByEmailSet reviewersByEmail() {
if (reviewersByEmail == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ReviewerByEmailSet.empty();
}
reviewersByEmail = notes().getReviewersByEmail();
@@ -758,7 +780,7 @@
public ReviewerSet pendingReviewers() {
if (pendingReviewers == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ReviewerSet.empty();
}
pendingReviewers = notes().getPendingReviewers();
@@ -776,7 +798,7 @@
public ReviewerByEmailSet pendingReviewersByEmail() {
if (pendingReviewersByEmail == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ReviewerByEmailSet.empty();
}
pendingReviewersByEmail = notes().getPendingReviewersByEmail();
@@ -786,7 +808,7 @@
public List<ReviewerStatusUpdate> reviewerUpdates() {
if (reviewerUpdates == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
reviewerUpdates = approvalsUtil.getReviewerUpdates(notes());
@@ -804,7 +826,7 @@
public Collection<HumanComment> publishedComments() {
if (publishedComments == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
publishedComments = commentsUtil.publishedHumanCommentsByChange(notes());
@@ -814,7 +836,7 @@
public Collection<RobotComment> robotComments() {
if (robotComments == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
robotComments = commentsUtil.robotCommentsByChange(notes());
@@ -824,7 +846,7 @@
public Integer unresolvedCommentCount() {
if (unresolvedCommentCount == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return null;
}
@@ -846,7 +868,7 @@
public Integer totalCommentCount() {
if (totalCommentCount == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return null;
}
@@ -863,7 +885,7 @@
public List<ChangeMessage> messages() {
if (messages == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyList();
}
messages = cmUtil.byChange(notes());
@@ -878,14 +900,24 @@
// evaluation.
List<SubmitRecord> records = submitRecords.get(options);
if (records == null) {
- if (!lazyLoad) {
+ if (storageConstraint != StorageConstraint.NOTEDB_ONLY) {
+ // Submit requirements are expensive. We allow loading them only if this change did not
+ // originate from the change index and we can invest the extra time.
+ logger.atWarning().log(
+ "Tried to load SubmitRecords for change fetched from index %s: %d",
+ project(), getId().get());
return Collections.emptyList();
}
records = submitRuleEvaluatorFactory.create(options).evaluate(this);
submitRecords.put(options, records);
if (!change().isClosed() && submitRecords.size() == 1) {
// Cache the SubmitRecord with allowClosed = !allowClosed as the SubmitRecord are the same.
- submitRecords.put(options.toBuilder().allowClosed(!options.allowClosed()).build(), records);
+ submitRecords.put(
+ options
+ .toBuilder()
+ .recomputeOnClosedChanges(!options.recomputeOnClosedChanges())
+ .build(),
+ records);
}
}
return records;
@@ -921,7 +953,7 @@
} else if (c.isWorkInProgress()) {
return null;
} else {
- if (!lazyLoad) {
+ if (!lazyload()) {
return null;
}
PatchSet ps = currentPatchSet();
@@ -953,12 +985,12 @@
@Nullable
public Boolean isMerge() {
- if (merge == null) {
+ if (parentCount == null) {
if (!loadCommitData()) {
return null;
}
}
- return merge;
+ return parentCount > 1;
}
public Set<Account.Id> editsByUser() {
@@ -967,7 +999,7 @@
public Map<Account.Id, Ref> editRefs() {
if (editsByUser == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyMap();
}
Change c = change();
@@ -999,7 +1031,7 @@
public Map<Account.Id, Ref> draftRefs() {
if (draftsByUser == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptyMap();
}
Change c = change();
@@ -1044,7 +1076,7 @@
public Set<Account.Id> reviewedBy() {
if (reviewedBy == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptySet();
}
Change c = change();
@@ -1076,7 +1108,7 @@
public Set<String> hashtags() {
if (hashtags == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return Collections.emptySet();
}
hashtags = notes().getHashtags();
@@ -1090,7 +1122,7 @@
public ImmutableListMultimap<Account.Id, String> stars() {
if (stars == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableListMultimap.of();
}
ImmutableListMultimap.Builder<Account.Id, String> b = ImmutableListMultimap.builder();
@@ -1108,7 +1140,7 @@
public ImmutableMap<Account.Id, StarRef> starRefs() {
if (starRefs == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableMap.of();
}
starRefs = requireNonNull(starredChangesUtil).byChange(legacyId);
@@ -1126,7 +1158,7 @@
if (stars != null) {
starsOf = StarsOf.create(accountId, stars.get(accountId));
} else {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableSet.of();
}
starsOf = StarsOf.create(accountId, starredChangesUtil.getLabels(accountId, legacyId));
@@ -1174,7 +1206,7 @@
public SetMultimap<NameKey, RefState> getRefStates() {
if (refStates == null) {
- if (!lazyLoad) {
+ if (!lazyload()) {
return ImmutableSetMultimap.of();
}
diff --git a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index 4922b57..1b6dc62 100644
--- a/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -262,7 +262,8 @@
}
if (includeSubmitRecords) {
- SubmitRuleOptions options = SubmitRuleOptions.builder().allowClosed(true).build();
+ SubmitRuleOptions options =
+ SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build();
eventFactory.addSubmitRecords(c, submitRuleEvaluatorFactory.create(options).evaluate(d));
}
diff --git a/java/com/google/gerrit/server/query/group/GroupIsVisibleToPredicate.java b/java/com/google/gerrit/server/query/group/GroupIsVisibleToPredicate.java
index 8248bf5..f6b194b 100644
--- a/java/com/google/gerrit/server/query/group/GroupIsVisibleToPredicate.java
+++ b/java/com/google/gerrit/server/query/group/GroupIsVisibleToPredicate.java
@@ -15,11 +15,11 @@
package com.google.gerrit.server.query.group;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.index.query.IsVisibleToPredicate;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.IndexUtils;
import com.google.gerrit.server.query.account.AccountQueryBuilder;
diff --git a/java/com/google/gerrit/server/query/group/GroupPredicates.java b/java/com/google/gerrit/server/query/group/GroupPredicates.java
index 5231c5a..992f60d 100644
--- a/java/com/google/gerrit/server/query/group/GroupPredicates.java
+++ b/java/com/google/gerrit/server/query/group/GroupPredicates.java
@@ -16,10 +16,10 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.FieldDef;
import com.google.gerrit.index.query.IndexPredicate;
import com.google.gerrit.index.query.Predicate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.group.GroupField;
import java.util.Locale;
diff --git a/java/com/google/gerrit/server/query/group/GroupQueryBuilder.java b/java/com/google/gerrit/server/query/group/GroupQueryBuilder.java
index fbc8d0e..89c802d 100644
--- a/java/com/google/gerrit/server/query/group/GroupQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/group/GroupQueryBuilder.java
@@ -22,6 +22,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.query.LimitPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryBuilder;
@@ -32,7 +33,6 @@
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.inject.Inject;
import java.io.IOException;
import java.util.List;
diff --git a/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java b/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
index 86c574d..9e56807 100644
--- a/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/group/GroupQueryProcessor.java
@@ -17,6 +17,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.query.group.GroupQueryBuilder.FIELD_LIMIT;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.query.AndSource;
import com.google.gerrit.index.query.IndexPredicate;
@@ -26,7 +27,6 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountLimits;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.group.GroupIndexCollection;
import com.google.gerrit.server.index.group.GroupIndexRewriter;
import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
diff --git a/java/com/google/gerrit/server/query/group/InternalGroupQuery.java b/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
index 5732873..b9b58b8 100644
--- a/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
+++ b/java/com/google/gerrit/server/query/group/InternalGroupQuery.java
@@ -21,10 +21,10 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.query.InternalQuery;
import com.google.gerrit.index.query.Predicate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.group.GroupIndexCollection;
import com.google.inject.Inject;
import java.util.List;
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java b/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
index 842ed2a..e981695 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
@@ -34,7 +34,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
@@ -113,8 +113,9 @@
}
@Override
- public void postUpdate(Context ctx) {
- assigneeChanged.fire(change, ctx.getAccount(), deletedAssignee, ctx.getWhen());
+ public void postUpdate(PostUpdateContext ctx) {
+ assigneeChanged.fire(
+ ctx.getChangeData(change), ctx.getAccount(), deletedAssignee, ctx.getWhen());
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteVote.java b/java/com/google/gerrit/server/restapi/change/DeleteVote.java
index 4b813df..433e71f 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteVote.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteVote.java
@@ -36,9 +36,11 @@
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.ChangeMessagesUtil;
+import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.change.AddToAttentionSetOp;
import com.google.gerrit.server.change.NotifyResolver;
import com.google.gerrit.server.change.ReviewerResource;
import com.google.gerrit.server.change.VoteResource;
@@ -53,11 +55,12 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.LabelVote;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.HashMap;
@@ -79,6 +82,8 @@
private final RemoveReviewerControl removeReviewerControl;
private final ProjectCache projectCache;
private final MessageIdGenerator messageIdGenerator;
+ private final AddToAttentionSetOp.Factory attentionSetOpfactory;
+ private final Provider<CurrentUser> currentUserProvider;
@Inject
DeleteVote(
@@ -92,7 +97,9 @@
NotifyResolver notifyResolver,
RemoveReviewerControl removeReviewerControl,
ProjectCache projectCache,
- MessageIdGenerator messageIdGenerator) {
+ MessageIdGenerator messageIdGenerator,
+ AddToAttentionSetOp.Factory attentionSetOpFactory,
+ Provider<CurrentUser> currentUserProvider) {
this.updateFactory = updateFactory;
this.approvalsUtil = approvalsUtil;
this.psUtil = psUtil;
@@ -104,6 +111,8 @@
this.removeReviewerControl = removeReviewerControl;
this.projectCache = projectCache;
this.messageIdGenerator = messageIdGenerator;
+ this.attentionSetOpfactory = attentionSetOpFactory;
+ this.currentUserProvider = currentUserProvider;
}
@Override
@@ -140,6 +149,14 @@
r.getReviewerUser().state(),
rsrc.getLabel(),
input));
+ if (!r.getReviewerUser().getAccountId().equals(currentUserProvider.get().getAccountId())) {
+ bu.addOp(
+ change.getId(),
+ attentionSetOpfactory.create(
+ r.getReviewerUser().getAccountId(),
+ /* reason= */ "Their vote was deleted",
+ /* notify= */ false));
+ }
bu.execute();
}
@@ -220,7 +237,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (changeMessage == null) {
return;
}
@@ -243,7 +260,7 @@
}
voteDeleted.fire(
- change,
+ ctx.getChangeData(change),
ps,
accountState,
newApprovals,
diff --git a/java/com/google/gerrit/server/restapi/change/GetBlame.java b/java/com/google/gerrit/server/restapi/change/GetBlame.java
index 12b4d44..04828f2 100644
--- a/java/com/google/gerrit/server/restapi/change/GetBlame.java
+++ b/java/com/google/gerrit/server/restapi/change/GetBlame.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.change.FileResource;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.InMemoryInserter;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.patch.AutoMerger;
import com.google.gerrit.server.project.InvalidChangeOperationException;
@@ -39,7 +40,6 @@
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
@@ -86,7 +86,7 @@
throws RestApiException, IOException, InvalidChangeOperationException {
Project.NameKey project = resource.getRevision().getChange().getProject();
try (Repository repository = repoManager.openRepository(project);
- ObjectInserter ins = repository.newObjectInserter();
+ InMemoryInserter ins = new InMemoryInserter(repository);
ObjectReader reader = ins.newReader();
RevWalk revWalk = new RevWalk(reader)) {
String refName =
@@ -115,7 +115,9 @@
result = blame(parents[0], path, repository, revWalk);
} else if (parents.length == 2) {
- ObjectId automerge = autoMerger.merge(repository, revWalk, ins, revCommit, mergeStrategy);
+ ObjectId automerge =
+ autoMerger.lookupFromGitOrMergeInMemory(
+ repository, revWalk, ins, revCommit, mergeStrategy);
result = blame(automerge, path, repository, revWalk);
} else {
diff --git a/java/com/google/gerrit/server/restapi/change/GetChange.java b/java/com/google/gerrit/server/restapi/change/GetChange.java
index 2f1c61e..c51bb91 100644
--- a/java/com/google/gerrit/server/restapi/change/GetChange.java
+++ b/java/com/google/gerrit/server/restapi/change/GetChange.java
@@ -62,6 +62,10 @@
@Option(name = "--meta", usage = "NoteDb meta SHA1")
String metaRevId = "";
+ public void setMetaRevId(String metaRevId) {
+ this.metaRevId = metaRevId == null ? "" : metaRevId;
+ }
+
@Option(name = "-O", usage = "Output option flags, in hex")
void setOptionFlagsHex(String hex) {
options.addAll(ListOption.fromBits(ListChangesOption.class, Integer.parseInt(hex, 16)));
diff --git a/java/com/google/gerrit/server/restapi/change/GetMetaDiff.java b/java/com/google/gerrit/server/restapi/change/GetMetaDiff.java
new file mode 100644
index 0000000..af23ba7
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/change/GetMetaDiff.java
@@ -0,0 +1,161 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.change;
+
+import static com.google.gerrit.entities.RefNames.changeMetaRef;
+
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.client.ListOption;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInfoDiffer;
+import com.google.gerrit.extensions.common.ChangeInfoDifference;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.PreconditionFailedException;
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.DynamicOptions;
+import com.google.gerrit.server.DynamicOptions.DynamicBean;
+import com.google.gerrit.server.change.ChangeResource;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jgit.errors.InvalidObjectIdException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.kohsuke.args4j.Option;
+
+/** Gets the diff for a change at two NoteDb meta SHA-1s. */
+public class GetMetaDiff
+ implements RestReadView<ChangeResource>,
+ DynamicOptions.BeanReceiver,
+ DynamicOptions.BeanProvider {
+
+ private final EnumSet<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class);
+ private final Map<String, DynamicBean> dynamicBeans = new HashMap<>();
+
+ private final Provider<GetChange> getChangeProvider;
+ private final GitRepositoryManager repoManager;
+
+ @Option(name = "-o", usage = "Output options")
+ public void addOption(ListChangesOption o) {
+ options.add(o);
+ }
+
+ @Option(name = "-O", usage = "Output option flags, in hex")
+ void setOptionFlagsHex(String hex) {
+ options.addAll(ListOption.fromBits(ListChangesOption.class, Integer.parseInt(hex, 16)));
+ }
+
+ @Option(name = "--old", usage = "old NoteDb meta SHA-1")
+ String oldMetaRevId = "";
+
+ public void setOldMetaRevId(@Nullable String oldMetaRevId) {
+ this.oldMetaRevId = oldMetaRevId == null ? "" : oldMetaRevId;
+ }
+
+ @Option(name = "--meta", usage = "new NoteDb meta SHA-1")
+ String metaRevId = "";
+
+ public void setNewMetaRevId(@Nullable String metaRevId) {
+ this.metaRevId = metaRevId == null ? "" : metaRevId;
+ }
+
+ @Inject
+ GetMetaDiff(Provider<GetChange> getChangeProvider, GitRepositoryManager repoManager) {
+ this.getChangeProvider = getChangeProvider;
+ this.repoManager = repoManager;
+ }
+
+ @Override
+ public void setDynamicBean(String plugin, DynamicOptions.DynamicBean dynamicBean) {
+ dynamicBeans.put(plugin, dynamicBean);
+ }
+
+ @Override
+ public DynamicBean getDynamicBean(String plugin) {
+ return dynamicBeans.get(plugin);
+ }
+
+ @Override
+ public Response<ChangeInfoDifference> apply(ChangeResource resource)
+ throws BadRequestException, PreconditionFailedException, IOException {
+ return Response.ok(
+ ChangeInfoDiffer.getDifference(getOldChangeInfo(resource), getNewChangeInfo(resource)));
+ }
+
+ private ChangeInfo getOldChangeInfo(ChangeResource resource)
+ throws BadRequestException, IOException, PreconditionFailedException {
+ GetChange getChange = createGetChange();
+ getChange.setMetaRevId(getOldMetaRevId(resource));
+ ChangeInfo oldChangeInfo;
+ try {
+ oldChangeInfo = getChange.apply(resource).value();
+ } catch (PreconditionFailedException e) {
+ oldChangeInfo = new ChangeInfo();
+ }
+ return oldChangeInfo;
+ }
+
+ private String getOldMetaRevId(ChangeResource resource)
+ throws IOException, BadRequestException, PreconditionFailedException {
+ if (!oldMetaRevId.isEmpty()) {
+ return oldMetaRevId;
+ }
+ String newMetaRevId = getNewMetaRevId(resource);
+ try (Repository repo = repoManager.openRepository(resource.getProject());
+ RevWalk rw = new RevWalk(repo)) {
+ ObjectId resourceId = ObjectId.fromString(newMetaRevId);
+ RevCommit commit = rw.parseCommit(resourceId);
+ return commit.getParentCount() == 0
+ ? resourceId.getName()
+ : commit.getParent(0).getId().getName();
+ } catch (InvalidObjectIdException e) {
+ throw new BadRequestException("invalid meta SHA1: " + newMetaRevId, e);
+ } catch (MissingObjectException e) {
+ throw new PreconditionFailedException(e.getMessage());
+ }
+ }
+
+ private ChangeInfo getNewChangeInfo(ChangeResource resource)
+ throws BadRequestException, PreconditionFailedException, IOException {
+ GetChange getChange = createGetChange();
+ getChange.setMetaRevId(getNewMetaRevId(resource));
+ return getChange.apply(resource).value();
+ }
+
+ private String getNewMetaRevId(ChangeResource resource) throws IOException {
+ if (!metaRevId.isEmpty()) {
+ return metaRevId;
+ }
+ try (Repository repo = repoManager.openRepository(resource.getProject())) {
+ return repo.exactRef(changeMetaRef(resource.getId())).getObjectId().getName();
+ }
+ }
+
+ private GetChange createGetChange() {
+ GetChange getChange = getChangeProvider.get();
+ options.forEach(getChange::addOption);
+ dynamicBeans.forEach(getChange::setDynamicBean);
+ return getChange;
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/change/ListChangeDrafts.java b/java/com/google/gerrit/server/restapi/change/ListChangeDrafts.java
index 3841dc1..65f90ae 100644
--- a/java/com/google/gerrit/server/restapi/change/ListChangeDrafts.java
+++ b/java/com/google/gerrit/server/restapi/change/ListChangeDrafts.java
@@ -16,6 +16,7 @@
import com.google.gerrit.entities.HumanComment;
import com.google.gerrit.extensions.common.CommentInfo;
+import com.google.gerrit.extensions.common.ContextLineInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
@@ -29,6 +30,7 @@
import com.google.inject.Singleton;
import java.util.List;
import java.util.Map;
+import org.kohsuke.args4j.Option;
@Singleton
public class ListChangeDrafts implements RestReadView<ChangeResource> {
@@ -36,6 +38,30 @@
private final Provider<CommentJson> commentJson;
private final CommentsUtil commentsUtil;
+ private boolean includeContext;
+ private int contextPadding;
+
+ /**
+ * Optional parameter. If set, the contextLines field of the {@link ContextLineInfo} of the
+ * response will contain the lines of the source file where the comment was written.
+ *
+ * @param context If true, comment context will be attached to the response
+ */
+ @Option(name = "--enable-context")
+ public void setContext(boolean context) {
+ this.includeContext = context;
+ }
+
+ /**
+ * Optional parameter. Works only if {@link #includeContext} is set to true. If {@link
+ * #contextPadding} is set, the context lines in the response will be padded with {@link
+ * #contextPadding} extra lines before and after the comment range.
+ */
+ @Option(name = "--context-padding")
+ public void setContextPadding(int contextPadding) {
+ this.contextPadding = contextPadding;
+ }
+
@Inject
ListChangeDrafts(
ChangeData.Factory changeDataFactory,
@@ -57,7 +83,7 @@
if (!rsrc.getUser().isIdentifiedUser()) {
throw new AuthException("Authentication required");
}
- return Response.ok(getCommentFormatter().format(listComments(rsrc)));
+ return Response.ok(getCommentFormatter(rsrc).format(listComments(rsrc)));
}
public List<CommentInfo> getComments(ChangeResource rsrc)
@@ -65,14 +91,18 @@
if (!rsrc.getUser().isIdentifiedUser()) {
throw new AuthException("Authentication required");
}
- return getCommentFormatter().formatAsList(listComments(rsrc));
+ return getCommentFormatter(rsrc).formatAsList(listComments(rsrc));
}
- private HumanCommentFormatter getCommentFormatter() {
+ private HumanCommentFormatter getCommentFormatter(ChangeResource rsrc) {
return commentJson
.get()
.setFillAccounts(false)
.setFillPatchSet(true)
+ .setFillCommentContext(includeContext)
+ .setContextPadding(contextPadding)
+ .setProjectKey(rsrc.getProject())
+ .setChangeId(rsrc.getId())
.newHumanCommentFormatter();
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/Module.java b/java/com/google/gerrit/server/restapi/change/Module.java
index 28f4114..f87c9a1 100644
--- a/java/com/google/gerrit/server/restapi/change/Module.java
+++ b/java/com/google/gerrit/server/restapi/change/Module.java
@@ -82,6 +82,7 @@
postOnCollection(CHANGE_KIND).to(CreateChange.class);
get(CHANGE_KIND).to(GetChange.class);
+ get(CHANGE_KIND, "meta_diff").to(GetMetaDiff.class);
post(CHANGE_KIND, "merge").to(CreateMergePatchSet.class);
get(CHANGE_KIND, "detail").to(GetDetail.class);
get(CHANGE_KIND, "topic").to(GetTopic.class);
diff --git a/java/com/google/gerrit/server/restapi/change/PostReview.java b/java/com/google/gerrit/server/restapi/change/PostReview.java
index 73b38b2..aad251a 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReview.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReview.java
@@ -123,7 +123,7 @@
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.CommentsRejectedException;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.LabelVote;
import com.google.gerrit.server.util.time.TimeUtil;
@@ -356,7 +356,8 @@
}
// Add WorkInProgressOp if requested.
- if (input.ready || input.workInProgress) {
+ if ((input.ready || input.workInProgress)
+ && didWorkInProgressChange(revision.getChange().isWorkInProgress(), input)) {
if (input.ready && input.workInProgress) {
output.error = ERROR_WIP_READY_MUTUALLY_EXCLUSIVE;
return Response.withStatusCode(SC_BAD_REQUEST, output);
@@ -405,6 +406,10 @@
return Response.ok(output);
}
+ private boolean didWorkInProgressChange(boolean currentWorkInProgress, ReviewInput input) {
+ return input.ready == currentWorkInProgress || input.workInProgress != currentWorkInProgress;
+ }
+
private NotifyHandling defaultNotify(Change c, ReviewInput in) {
boolean workInProgress = c.isWorkInProgress();
if (in.workInProgress) {
@@ -923,7 +928,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
if (message == null) {
return;
}
@@ -963,7 +968,13 @@
}
}
commentAdded.fire(
- notes.getChange(), ps, user.state(), comment, approvals, oldApprovals, ctx.getWhen());
+ ctx.getChangeData(notes),
+ ps,
+ user.state(),
+ comment,
+ approvals,
+ oldApprovals,
+ ctx.getWhen());
}
private boolean insertComments(ChangeContext ctx, List<RobotComment> newRobotComments)
diff --git a/java/com/google/gerrit/server/restapi/change/ReplyAttentionSetUpdates.java b/java/com/google/gerrit/server/restapi/change/ReplyAttentionSetUpdates.java
index a1bd678..4723d70 100644
--- a/java/com/google/gerrit/server/restapi/change/ReplyAttentionSetUpdates.java
+++ b/java/com/google/gerrit/server/restapi/change/ReplyAttentionSetUpdates.java
@@ -123,7 +123,9 @@
bu.addOp(changeNotes.getChangeId(), new AttentionSetUnchangedOp());
return;
}
- if (serviceUserClassifier.isServiceUser(currentUser.getAccountId())) {
+ boolean isReadyForReview = isReadyForReview(changeNotes, input);
+
+ if (isReadyForReview && serviceUserClassifier.isServiceUser(currentUser.getAccountId())) {
botsWithNegativeLabelsAddOwnerAndUploader(bu, changeNotes, input);
return;
}
@@ -131,7 +133,7 @@
processRules(
bu,
changeNotes,
- isReadyForReview(changeNotes, input),
+ isReadyForReview,
currentUser,
getAllNewComments(changeNotes, input, currentUser));
}
diff --git a/java/com/google/gerrit/server/restapi/change/Restore.java b/java/com/google/gerrit/server/restapi/change/Restore.java
index 7faf8e0..ace89ac8 100644
--- a/java/com/google/gerrit/server/restapi/change/Restore.java
+++ b/java/com/google/gerrit/server/restapi/change/Restore.java
@@ -47,7 +47,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
@@ -148,7 +148,7 @@
}
@Override
- public void postUpdate(Context ctx) {
+ public void postUpdate(PostUpdateContext ctx) {
try {
ReplyToChangeSender emailSender =
restoredSenderFactory.create(ctx.getProject(), change.getId());
@@ -161,7 +161,11 @@
logger.atSevere().withCause(e).log("Cannot email update for change %s", change.getId());
}
changeRestored.fire(
- change, patchSet, ctx.getAccount(), Strings.emptyToNull(input.message), ctx.getWhen());
+ ctx.getChangeData(change),
+ patchSet,
+ ctx.getAccount(),
+ Strings.emptyToNull(input.message),
+ ctx.getWhen());
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
index cb91faa..7414bf4 100644
--- a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
+++ b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
@@ -75,7 +75,7 @@
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.CommitMessageUtil;
import com.google.gerrit.server.util.time.TimeUtil;
@@ -614,10 +614,10 @@
}
@Override
- public void postUpdate(Context ctx) throws Exception {
+ public void postUpdate(PostUpdateContext ctx) throws Exception {
changeReverted.fire(
- change,
- changeNotesFactory.createChecked(ctx.getProject(), revertChangeId).getChange(),
+ ctx.getChangeData(change),
+ ctx.getChangeData(changeNotesFactory.createChecked(ctx.getProject(), revertChangeId)),
ctx.getWhen());
try {
RevertedSender emailSender = revertedSenderFactory.create(ctx.getProject(), change.getId());
diff --git a/java/com/google/gerrit/server/restapi/change/Submit.java b/java/com/google/gerrit/server/restapi/change/Submit.java
index 790b2db..801340b 100644
--- a/java/com/google/gerrit/server/restapi/change/Submit.java
+++ b/java/com/google/gerrit/server/restapi/change/Submit.java
@@ -311,7 +311,7 @@
throw new StorageException("Could not determine problems for the change", e);
}
- ChangeData cd = changeDataFactory.create(resource.getNotes());
+ ChangeData cd = resource.getChangeResource().getChangeData();
try {
MergeOp.checkSubmitRule(cd, false);
} catch (ResourceConflictException e) {
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 0a5692e..c3dd1b5 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -320,17 +320,12 @@
PluginConfigInfo info = new PluginConfigInfo();
info.hasAvatars = toBoolean(avatar.hasImplementation());
info.jsResourcePaths = new ArrayList<>();
- info.htmlResourcePaths = new ArrayList<>();
plugins.runEach(
plugin -> {
String path =
String.format(
"plugins/%s/%s", plugin.getPluginName(), plugin.getJavaScriptResourcePath());
- if (path.endsWith(".html")) {
- info.htmlResourcePaths.add(path);
- } else {
- info.jsResourcePaths.add(path);
- }
+ info.jsResourcePaths.add(path);
});
return info;
}
diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
index 613c805..0ec63ba 100644
--- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java
+++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
@@ -21,6 +21,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.api.groups.GroupInput;
@@ -45,7 +46,6 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.group.GroupResolver;
import com.google.gerrit.server.group.GroupResource;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.group.db.GroupsUpdate;
diff --git a/java/com/google/gerrit/server/restapi/group/GetAuditLog.java b/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
index 8a469f1..e3aa0f3 100644
--- a/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
+++ b/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
@@ -14,12 +14,14 @@
package com.google.gerrit.server.restapi.group;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Comparator.comparing;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.AccountGroupByIdAudit;
import com.google.gerrit.entities.AccountGroupMemberAudit;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.GroupAuditEventInfo;
import com.google.gerrit.extensions.common.GroupInfo;
@@ -33,7 +35,6 @@
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.group.GroupResource;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -42,7 +43,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
+import java.util.Map;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Repository;
@@ -105,14 +106,17 @@
member));
}
}
-
- for (AccountGroupByIdAudit auditEvent :
- groups.getSubgroupsAudit(allUsersRepo, group.getGroupUUID())) {
+ List<AccountGroupByIdAudit> subGroupsAudit =
+ groups.getSubgroupsAudit(allUsersRepo, group.getGroupUUID());
+ Map<AccountGroup.UUID, InternalGroup> groups =
+ groupCache.get(
+ subGroupsAudit.stream().map(a -> a.includeUuid()).collect(toImmutableList()));
+ for (AccountGroupByIdAudit auditEvent : subGroupsAudit) {
AccountGroup.UUID includedGroupUUID = auditEvent.includeUuid();
- Optional<InternalGroup> includedGroup = groupCache.get(includedGroupUUID);
+ InternalGroup includedGroup = groups.get(includedGroupUUID);
GroupInfo member;
- if (includedGroup.isPresent()) {
- member = groupJson.format(new InternalGroupDescription(includedGroup.get()));
+ if (includedGroup != null) {
+ member = groupJson.format(new InternalGroupDescription(includedGroup));
} else {
member = new GroupInfo();
member.id = Url.encode(includedGroupUUID.get());
diff --git a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
index e0cfb1e..08cc974 100644
--- a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
+++ b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
@@ -87,7 +87,7 @@
final CurrentUser user = self.get();
if (user instanceof AnonymousUser) {
throw new AuthException("Authentication required");
- } else if (!(user.isIdentifiedUser())) {
+ } else if (!(user.isIdentifiedUser() || user.isInternalUser())) {
throw new ResourceNotFoundException(id);
}
diff --git a/java/com/google/gerrit/server/restapi/group/ListGroups.java b/java/com/google/gerrit/server/restapi/group/ListGroups.java
index 3e2a577..96402be 100644
--- a/java/com/google/gerrit/server/restapi/group/ListGroups.java
+++ b/java/com/google/gerrit/server/restapi/group/ListGroups.java
@@ -15,12 +15,12 @@
package com.google.gerrit.server.restapi.group;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.toList;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
-import com.google.common.collect.Streams;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
@@ -57,7 +57,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
-import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -273,10 +272,12 @@
throws IOException, ConfigInvalidException, PermissionBackendException {
Pattern pattern = getRegexPattern();
Stream<GroupDescription.Internal> existingGroups =
- getAllExistingGroups()
- .filter(group -> isRelevant(pattern, group))
- .map(this::loadGroup)
- .flatMap(Streams::stream)
+ loadGroups(
+ getAllExistingGroups()
+ .filter(group -> isRelevant(pattern, group))
+ .map(g -> g.getUUID())
+ .collect(toImmutableSet()))
+ .stream()
.filter(this::isVisible)
.sorted(GROUP_COMPARATOR)
.skip(start);
@@ -359,11 +360,13 @@
throws IOException, ConfigInvalidException, PermissionBackendException {
Pattern pattern = getRegexPattern();
Stream<? extends GroupDescription.Internal> foundGroups =
- groups
- .getAllGroupReferences()
- .filter(group -> isRelevant(pattern, group))
- .map(this::loadGroup)
- .flatMap(Streams::stream)
+ loadGroups(
+ groups
+ .getAllGroupReferences()
+ .filter(group -> isRelevant(pattern, group))
+ .map(g -> g.getUUID())
+ .collect(toImmutableSet()))
+ .stream()
.filter(this::isVisible)
.filter(filter)
.sorted(GROUP_COMPARATOR)
@@ -379,8 +382,10 @@
return groupInfos;
}
- private Optional<GroupDescription.Internal> loadGroup(GroupReference groupReference) {
- return groupCache.get(groupReference.getUUID()).map(InternalGroupDescription::new);
+ private Set<GroupDescription.Internal> loadGroups(Collection<AccountGroup.UUID> groupUuids) {
+ return groupCache.get(groupUuids).values().stream()
+ .map(InternalGroupDescription::new)
+ .collect(toImmutableSet());
}
private List<GroupInfo> getGroupsOwnedBy(String id)
diff --git a/java/com/google/gerrit/server/restapi/group/ListMembers.java b/java/com/google/gerrit/server/restapi/group/ListMembers.java
index 5b3e8dc..218eb98 100644
--- a/java/com/google/gerrit/server/restapi/group/ListMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/ListMembers.java
@@ -23,6 +23,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
@@ -31,7 +32,6 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.group.GroupResource;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.inject.Inject;
@@ -144,23 +144,21 @@
private Set<Account.Id> getIndirectMemberIds(
GroupDescription.Internal group, HashSet<AccountGroup.UUID> seenGroups) {
Set<Account.Id> indirectMembers = new HashSet<>();
+ Set<AccountGroup.UUID> subgroupMembersToLoad = new HashSet<>();
for (AccountGroup.UUID subgroupUuid : group.getSubgroups()) {
if (!seenGroups.contains(subgroupUuid)) {
seenGroups.add(subgroupUuid);
-
- Set<Account.Id> subgroupMembers =
- groupCache
- .get(subgroupUuid)
- .map(InternalGroupDescription::new)
- .map(
- subgroup -> {
- GroupControl subgroupControl = groupControlFactory.controlFor(subgroup);
- return getTransitiveMemberIds(subgroup, subgroupControl, seenGroups);
- })
- .orElseGet(ImmutableSet::of);
- indirectMembers.addAll(subgroupMembers);
+ subgroupMembersToLoad.add(subgroupUuid);
}
}
+ groupCache.get(subgroupMembersToLoad).values().stream()
+ .map(InternalGroupDescription::new)
+ .forEach(
+ subgroup -> {
+ GroupControl subgroupControl = groupControlFactory.controlFor(subgroup);
+ indirectMembers.addAll(getTransitiveMemberIds(subgroup, subgroupControl, seenGroups));
+ });
+
return indirectMembers;
}
diff --git a/java/com/google/gerrit/server/restapi/group/QueryGroups.java b/java/com/google/gerrit/server/restapi/group/QueryGroups.java
index 380d42e..26e8459 100644
--- a/java/com/google/gerrit/server/restapi/group/QueryGroups.java
+++ b/java/com/google/gerrit/server/restapi/group/QueryGroups.java
@@ -16,6 +16,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.client.ListGroupsOption;
import com.google.gerrit.extensions.client.ListOption;
import com.google.gerrit.extensions.common.GroupInfo;
@@ -26,7 +27,6 @@
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.index.query.QueryResult;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.InternalGroupDescription;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.query.group.GroupQueryBuilder;
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index faab241..f3b2bad 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -37,6 +37,7 @@
import com.google.gerrit.server.ProjectUtil;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.ProjectOwnerGroupsProvider;
import com.google.gerrit.server.group.GroupResolver;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -60,6 +61,7 @@
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -79,6 +81,8 @@
private final PluginItemContext<ProjectNameLockManager> lockManager;
private final ProjectCreator projectCreator;
+ private final Config gerritConfig;
+
@Inject
CreateProject(
ProjectCreator projectCreator,
@@ -90,7 +94,8 @@
Provider<PutConfig> putConfig,
AllProjectsName allProjects,
AllUsersName allUsers,
- PluginItemContext<ProjectNameLockManager> lockManager) {
+ PluginItemContext<ProjectNameLockManager> lockManager,
+ @GerritServerConfig Config gerritConfig) {
this.projectsCollection = projectsCollection;
this.projectCreator = projectCreator;
this.groupResolver = groupResolver;
@@ -101,6 +106,7 @@
this.allProjects = allProjects;
this.allUsers = allUsers;
this.lockManager = lockManager;
+ this.gerritConfig = gerritConfig;
}
@Override
@@ -190,18 +196,18 @@
private List<String> normalizeBranchNames(List<String> branches) throws BadRequestException {
if (branches == null || branches.isEmpty()) {
- return Collections.singletonList(Constants.R_HEADS + Constants.MASTER);
+ // Use host-level default for HEAD or fall back to 'master' if nothing else was specified in
+ // the input.
+ String defaultBranch = gerritConfig.getString("gerrit", null, "defaultBranch");
+ defaultBranch =
+ defaultBranch != null
+ ? normalizeAndValidateBranch(defaultBranch)
+ : Constants.R_HEADS + Constants.MASTER;
+ return Collections.singletonList(defaultBranch);
}
-
List<String> normalizedBranches = new ArrayList<>();
for (String branch : branches) {
- while (branch.startsWith("/")) {
- branch = branch.substring(1);
- }
- branch = RefNames.fullName(branch);
- if (!Repository.isValidRefName(branch)) {
- throw new BadRequestException(String.format("Branch \"%s\" is not a valid name.", branch));
- }
+ branch = normalizeAndValidateBranch(branch);
if (!normalizedBranches.contains(branch)) {
normalizedBranches.add(branch);
}
@@ -209,6 +215,17 @@
return normalizedBranches;
}
+ private String normalizeAndValidateBranch(String branch) throws BadRequestException {
+ while (branch.startsWith("/")) {
+ branch = branch.substring(1);
+ }
+ branch = RefNames.fullName(branch);
+ if (!Repository.isValidRefName(branch)) {
+ throw new BadRequestException(String.format("Branch \"%s\" is not a valid name.", branch));
+ }
+ return branch;
+ }
+
static class ValidBranchListener implements ProjectCreationValidationListener {
@Override
public void validateNewProject(CreateProjectArgs args) throws ValidationException {
diff --git a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
index c5423e6..abd47e9 100644
--- a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
+++ b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
@@ -29,7 +29,6 @@
import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.git.GarbageCollection;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.ioutil.HexFormat;
import com.google.gerrit.server.project.ProjectResource;
@@ -67,7 +66,7 @@
DynamicItem<UrlFormatter> urlFormatter) {
this.workQueue = workQueue;
this.urlFormatter = urlFormatter;
- this.canGC = repoManager instanceof LocalDiskRepositoryManager;
+ this.canGC = repoManager.canPerformGC();
this.garbageCollectionFactory = garbageCollectionFactory;
}
diff --git a/java/com/google/gerrit/server/rules/DefaultSubmitRule.java b/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
index 4592100..e670dc2 100644
--- a/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
+++ b/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.rules;
+import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.gerrit.server.project.ProjectCache.illegalState;
@@ -22,7 +23,6 @@
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.SubmitRecord;
-import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.server.project.ProjectCache;
@@ -76,32 +76,17 @@
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.status = SubmitRecord.Status.OK;
- List<LabelType> labelTypes;
- List<PatchSetApproval> approvals;
- try {
- labelTypes = cd.getLabelTypes().getLabelTypes();
- approvals = cd.currentApprovals();
- } catch (StorageException e) {
- logger.atSevere().withCause(e).log(
- "Unable to fetch labels and approvals for change %s", cd.getId());
-
- submitRecord.errorMessage = "Unable to fetch labels and approvals for the change";
- submitRecord.status = SubmitRecord.Status.RULE_ERROR;
- return Optional.of(submitRecord);
- }
-
+ List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
+ List<PatchSetApproval> approvals = cd.currentApprovals();
submitRecord.labels = new ArrayList<>(labelTypes.size());
for (LabelType t : labelTypes) {
LabelFunction labelFunction = t.getFunction();
- if (labelFunction == null) {
- logger.atSevere().log(
- "Unable to find the LabelFunction for label %s, change %s", t.getName(), cd.getId());
-
- submitRecord.errorMessage = "Unable to find the LabelFunction for label " + t.getName();
- submitRecord.status = SubmitRecord.Status.RULE_ERROR;
- return Optional.of(submitRecord);
- }
+ checkState(
+ labelFunction != null,
+ "Unable to find the LabelFunction for label %s, change %s",
+ t.getName(),
+ cd.getId());
Collection<PatchSetApproval> approvalsForLabel = getApprovalsForLabel(approvals, t);
SubmitRecord.Label label = labelFunction.check(t, approvalsForLabel);
diff --git a/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java b/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
index b2bfbd5..4541330 100644
--- a/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
+++ b/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
@@ -17,14 +17,12 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.entities.SubmitRequirement;
-import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.AbstractModule;
@@ -40,11 +38,6 @@
*/
@Singleton
public class IgnoreSelfApprovalRule implements SubmitRule {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private static final String E_UNABLE_TO_FETCH_UPLOADER = "Unable to fetch uploader";
- private static final String E_UNABLE_TO_FETCH_LABELS =
- "Unable to fetch labels and approvals for the change";
-
public static class Module extends AbstractModule {
@Override
public void configure() {
@@ -56,16 +49,8 @@
@Override
public Optional<SubmitRecord> evaluate(ChangeData cd) {
- List<LabelType> labelTypes;
- List<PatchSetApproval> approvals;
- try {
- labelTypes = cd.getLabelTypes().getLabelTypes();
- approvals = cd.currentApprovals();
- } catch (StorageException e) {
- logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_LABELS);
- return ruleError(E_UNABLE_TO_FETCH_LABELS);
- }
-
+ List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
+ List<PatchSetApproval> approvals = cd.currentApprovals();
boolean shouldIgnoreSelfApproval =
labelTypes.stream().anyMatch(LabelType::isIgnoreSelfApproval);
if (!shouldIgnoreSelfApproval) {
@@ -73,14 +58,7 @@
return Optional.empty();
}
- Account.Id uploader;
- try {
- uploader = cd.currentPatchSet().uploader();
- } catch (StorageException e) {
- logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_UPLOADER);
- return ruleError(E_UNABLE_TO_FETCH_UPLOADER);
- }
-
+ Account.Id uploader = cd.currentPatchSet().uploader();
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.status = SubmitRecord.Status.OK;
submitRecord.labels = new ArrayList<>(labelTypes.size());
@@ -140,13 +118,6 @@
return false;
}
- private static Optional<SubmitRecord> ruleError(String reason) {
- SubmitRecord submitRecord = new SubmitRecord();
- submitRecord.errorMessage = reason;
- submitRecord.status = SubmitRecord.Status.RULE_ERROR;
- return Optional.of(submitRecord);
- }
-
@VisibleForTesting
static Collection<PatchSetApproval> filterOutPositiveApprovalsOfUser(
Collection<PatchSetApproval> approvals, Account.Id user) {
diff --git a/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java b/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
index 57c4832..3dc5be0 100644
--- a/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
+++ b/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
@@ -16,9 +16,6 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.project.ProjectCache.illegalState;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.createRuleError;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.defaultRuleError;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.defaultTypeError;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
@@ -61,6 +58,9 @@
*/
public class PrologRuleEvaluator {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private static final String DEFAULT_MSG = "Error evaluating project rules, check server log";
+
/**
* List of characters to allow in the label name, when an invalid name is used. Dash is allowed as
* it can't be the first character: we use a prefix.
@@ -289,6 +289,13 @@
return VALID_LABEL_MATCHER.retainFrom(name);
}
+ private static SubmitRecord createRuleError(String err) {
+ SubmitRecord rec = new SubmitRecord();
+ rec.status = SubmitRecord.Status.RULE_ERROR;
+ rec.errorMessage = err;
+ return rec;
+ }
+
private SubmitRecord invalidResult(Term rule, Term record, String reason) {
return ruleError(
String.format(
@@ -311,7 +318,7 @@
private SubmitRecord ruleError(String err, Exception e) {
if (opts.logErrors()) {
logger.atSevere().withCause(e).log(err);
- return defaultRuleError();
+ return createRuleError(DEFAULT_MSG);
}
return createRuleError(err);
}
@@ -389,7 +396,7 @@
private SubmitTypeRecord typeError(String err, Exception e) {
if (opts.logErrors()) {
logger.atSevere().withCause(e).log(err);
- return defaultTypeError();
+ return typeError(DEFAULT_MSG);
}
return SubmitTypeRecord.error(err);
}
diff --git a/java/com/google/gerrit/server/schema/MariaDBAccountPatchReviewStore.java b/java/com/google/gerrit/server/schema/MariaDBAccountPatchReviewStore.java
index b0a3370..dd82be2 100644
--- a/java/com/google/gerrit/server/schema/MariaDBAccountPatchReviewStore.java
+++ b/java/com/google/gerrit/server/schema/MariaDBAccountPatchReviewStore.java
@@ -22,6 +22,7 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.SQLException;
+import java.sql.Statement;
import org.eclipse.jgit.lib.Config;
@Singleton
@@ -50,4 +51,17 @@
return new StorageException(op + " failure on ACCOUNT_PATCH_REVIEWS", err);
}
}
+
+ @Override
+ protected void doCreateTable(Statement stmt) throws SQLException {
+ stmt.executeUpdate(
+ "CREATE TABLE IF NOT EXISTS account_patch_reviews ("
+ + "account_id INTEGER DEFAULT 0 NOT NULL, "
+ + "change_id INTEGER DEFAULT 0 NOT NULL, "
+ + "patch_set_id INTEGER DEFAULT 0 NOT NULL, "
+ + "file_name VARCHAR(255) DEFAULT '' NOT NULL, "
+ + "CONSTRAINT primary_key_account_patch_reviews "
+ + "PRIMARY KEY (change_id, patch_set_id, account_id, file_name)"
+ + ")");
+ }
}
diff --git a/java/com/google/gerrit/server/schema/SchemaCreatorImpl.java b/java/com/google/gerrit/server/schema/SchemaCreatorImpl.java
index de9374e..bda3dc4 100644
--- a/java/com/google/gerrit/server/schema/SchemaCreatorImpl.java
+++ b/java/com/google/gerrit/server/schema/SchemaCreatorImpl.java
@@ -18,6 +18,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.metrics.MetricMaker;
@@ -29,7 +30,6 @@
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.AuditLogFormatter;
import com.google.gerrit.server.group.db.GroupConfig;
import com.google.gerrit.server.group.db.GroupNameNotes;
diff --git a/java/com/google/gerrit/server/schema/Schema_184.java b/java/com/google/gerrit/server/schema/Schema_184.java
index c14ae8a..85d4740 100644
--- a/java/com/google/gerrit/server/schema/Schema_184.java
+++ b/java/com/google/gerrit/server/schema/Schema_184.java
@@ -17,12 +17,12 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.AuditLogFormatter;
import com.google.gerrit.server.group.db.GroupConfig;
import com.google.gerrit.server.group.db.GroupNameNotes;
diff --git a/java/com/google/gerrit/server/ssh/HostKey.java b/java/com/google/gerrit/server/ssh/HostKey.java
new file mode 100644
index 0000000..9397612
--- /dev/null
+++ b/java/com/google/gerrit/server/ssh/HostKey.java
@@ -0,0 +1,33 @@
+// 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.ssh;
+
+public class HostKey {
+ private final String host;
+ private final byte[] key;
+
+ public HostKey(String host, byte[] key) {
+ this.host = host;
+ this.key = key;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+}
diff --git a/java/com/google/gerrit/server/ssh/NoSshInfo.java b/java/com/google/gerrit/server/ssh/NoSshInfo.java
index 91a949b..a716398 100644
--- a/java/com/google/gerrit/server/ssh/NoSshInfo.java
+++ b/java/com/google/gerrit/server/ssh/NoSshInfo.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.ssh;
-import com.jcraft.jsch.HostKey;
import java.util.Collections;
import java.util.List;
diff --git a/java/com/google/gerrit/server/ssh/SshInfo.java b/java/com/google/gerrit/server/ssh/SshInfo.java
index 430846d..ec5a579 100644
--- a/java/com/google/gerrit/server/ssh/SshInfo.java
+++ b/java/com/google/gerrit/server/ssh/SshInfo.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.ssh;
-import com.jcraft.jsch.HostKey;
import java.util.List;
public interface SshInfo {
diff --git a/java/com/google/gerrit/server/submit/MergeOp.java b/java/com/google/gerrit/server/submit/MergeOp.java
index f486650..ccea90c 100644
--- a/java/com/google/gerrit/server/submit/MergeOp.java
+++ b/java/com/google/gerrit/server/submit/MergeOp.java
@@ -120,7 +120,7 @@
private static final SubmitRuleOptions SUBMIT_RULE_OPTIONS = SubmitRuleOptions.builder().build();
private static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_ALLOW_CLOSED =
- SUBMIT_RULE_OPTIONS.toBuilder().allowClosed(true).build();
+ SUBMIT_RULE_OPTIONS.toBuilder().recomputeOnClosedChanges(true).build();
public static class CommitStatus {
private final ImmutableMap<Change.Id, ChangeData> changes;
diff --git a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
index db48cce..cc3b75d 100644
--- a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
+++ b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import java.io.IOException;
import java.util.ArrayList;
@@ -270,7 +270,7 @@
}
@Override
- public void postUpdateImpl(Context ctx) {
+ public void postUpdateImpl(PostUpdateContext ctx) {
if (rebaseOp != null) {
rebaseOp.postUpdate(ctx);
}
diff --git a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
index 69207ac..a957b39 100644
--- a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
+++ b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
@@ -48,7 +48,7 @@
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
-import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import java.io.IOException;
import java.util.ArrayList;
@@ -463,7 +463,7 @@
}
@Override
- public final void postUpdate(Context ctx) throws Exception {
+ public final void postUpdate(PostUpdateContext ctx) throws Exception {
if (changeAlreadyMerged) {
// TODO(dborowitz): This is suboptimal behavior in the presence of retries: postUpdate steps
// will never get run for changes that submitted successfully on any but the final attempt.
@@ -518,7 +518,7 @@
}
if (mergeResultRev != null && !args.dryrun) {
args.changeMerged.fire(
- updatedChange,
+ ctx.getChangeData(updatedChange),
mergedPatchSet,
args.accountCache.get(submitter.accountId()).orElse(null),
args.mergeTip.getCurrentTip().name(),
@@ -542,10 +542,10 @@
}
/**
- * @see #postUpdate(Context)
+ * @see #postUpdate(PostUpdateContext)
* @param ctx
*/
- protected void postUpdateImpl(Context ctx) throws Exception {}
+ protected void postUpdateImpl(PostUpdateContext ctx) throws Exception {}
/**
* Amend the commit with gitlink update
diff --git a/java/com/google/gerrit/server/update/BatchUpdate.java b/java/com/google/gerrit/server/update/BatchUpdate.java
index 7fdf833..3b0cd9a 100644
--- a/java/com/google/gerrit/server/update/BatchUpdate.java
+++ b/java/com/google/gerrit/server/update/BatchUpdate.java
@@ -64,6 +64,7 @@
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.NoSuchRefException;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.assistedinject.Assisted;
@@ -74,9 +75,11 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.TimeZone;
import java.util.TreeMap;
+import java.util.function.Function;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
@@ -134,7 +137,7 @@
checkDifferentProject(updates);
try {
- List<ListenableFuture<?>> indexFutures = new ArrayList<>();
+ List<ListenableFuture<ChangeData>> indexFutures = new ArrayList<>();
List<ChangesHandle> changesHandles = new ArrayList<>(updates.size());
try {
for (BatchUpdate u : updates) {
@@ -156,7 +159,11 @@
}
}
- ((ListenableFuture<?>) Futures.allAsList(indexFutures)).get();
+ Map<Change.Id, ChangeData> changeDatas =
+ Futures.allAsList(indexFutures).get().stream()
+ // filter out null values that were returned for change deletions
+ .filter(Objects::nonNull)
+ .collect(toMap(cd -> cd.change().getId(), Function.identity()));
// Fire ref update events only after all mutations are finished, since callers may assume a
// patch set ref being created means the change was created, or a branch advancing meaning
@@ -165,7 +172,7 @@
if (!dryrun) {
for (BatchUpdate u : updates) {
- u.executePostOps();
+ u.executePostOps(changeDatas);
}
}
} catch (Exception e) {
@@ -340,6 +347,19 @@
}
}
+ private class PostUpdateContextImpl extends ContextImpl implements PostUpdateContext {
+ private final Map<Change.Id, ChangeData> changeDatas;
+
+ PostUpdateContextImpl(Map<Change.Id, ChangeData> changeDatas) {
+ this.changeDatas = changeDatas;
+ }
+
+ @Override
+ public ChangeData getChangeData(Change change) {
+ return changeDatas.computeIfAbsent(change.getId(), id -> changeDataFactory.create(change));
+ }
+ }
+
/** Per-change result status from {@link #executeChangeOps}. */
private enum ChangeResult {
SKIPPED,
@@ -348,6 +368,7 @@
}
private final GitRepositoryManager repoManager;
+ private final ChangeData.Factory changeDataFactory;
private final ChangeNotes.Factory changeNotesFactory;
private final ChangeUpdate.Factory changeUpdateFactory;
private final NoteDbUpdateManager.Factory updateManagerFactory;
@@ -377,6 +398,7 @@
BatchUpdate(
GitRepositoryManager repoManager,
@GerritPersonIdent PersonIdent serverIdent,
+ ChangeData.Factory changeDataFactory,
ChangeNotes.Factory changeNotesFactory,
ChangeUpdate.Factory changeUpdateFactory,
NoteDbUpdateManager.Factory updateManagerFactory,
@@ -386,6 +408,7 @@
@Assisted CurrentUser user,
@Assisted Timestamp when) {
this.repoManager = repoManager;
+ this.changeDataFactory = changeDataFactory;
this.changeNotesFactory = changeNotesFactory;
this.changeUpdateFactory = changeUpdateFactory;
this.updateManagerFactory = updateManagerFactory;
@@ -589,12 +612,12 @@
BatchUpdate.this.executed = manager.isExecuted();
}
- List<ListenableFuture<?>> startIndexFutures() {
+ List<ListenableFuture<ChangeData>> startIndexFutures() {
if (dryrun) {
return ImmutableList.of();
}
logDebug("Reindexing %d changes", results.size());
- List<ListenableFuture<?>> indexFutures = new ArrayList<>(results.size());
+ List<ListenableFuture<ChangeData>> indexFutures = new ArrayList<>(results.size());
for (Map.Entry<Change.Id, ChangeResult> e : results.entrySet()) {
Change.Id id = e.getKey();
switch (e.getValue()) {
@@ -687,8 +710,8 @@
return new ChangeContextImpl(notes);
}
- private void executePostOps() throws Exception {
- ContextImpl ctx = new ContextImpl();
+ private void executePostOps(Map<Change.Id, ChangeData> changeDatas) throws Exception {
+ PostUpdateContextImpl ctx = new PostUpdateContextImpl(changeDatas);
for (BatchUpdateOp op : ops.values()) {
try (TraceContext.TraceTimer ignored =
TraceContext.newTimer(op.getClass().getSimpleName() + "#postUpdate", Metadata.empty())) {
diff --git a/java/com/google/gerrit/server/update/PostUpdateContext.java b/java/com/google/gerrit/server/update/PostUpdateContext.java
new file mode 100644
index 0000000..d4d1f62
--- /dev/null
+++ b/java/com/google/gerrit/server/update/PostUpdateContext.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.update;
+
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.query.change.ChangeData;
+
+/** Context for performing the {@link BatchUpdateOp#postUpdate} phase. */
+public interface PostUpdateContext extends Context {
+ /**
+ * Get the change data for the specified change.
+ *
+ * <p>If the change data has been computed previously, because the change has been indexed after
+ * an update or because this method has been invoked before, the cached change data instance is
+ * returned.
+ *
+ * @param change the change for which the change data should be returned
+ */
+ ChangeData getChangeData(Change change);
+
+ default ChangeData getChangeData(ChangeNotes changeNotes) {
+ return getChangeData(changeNotes.getChange());
+ }
+}
diff --git a/java/com/google/gerrit/server/update/RepoOnlyOp.java b/java/com/google/gerrit/server/update/RepoOnlyOp.java
index 7e9c47e..c3e3948 100644
--- a/java/com/google/gerrit/server/update/RepoOnlyOp.java
+++ b/java/com/google/gerrit/server/update/RepoOnlyOp.java
@@ -35,5 +35,5 @@
* @param ctx context
*/
// TODO(dborowitz): Support async operations?
- default void postUpdate(Context ctx) throws Exception {}
+ default void postUpdate(PostUpdateContext ctx) throws Exception {}
}
diff --git a/java/com/google/gerrit/sshd/BUILD b/java/com/google/gerrit/sshd/BUILD
index a5b88b4..0668c1e 100644
--- a/java/com/google/gerrit/sshd/BUILD
+++ b/java/com/google/gerrit/sshd/BUILD
@@ -4,6 +4,7 @@
name = "sshd",
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
+ runtime_deps = ["//lib:jsch"],
deps = [
"//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/common:server",
@@ -28,7 +29,7 @@
"//lib:guava",
"//lib:jgit",
"//lib:jgit-archive",
- "//lib:jsch",
+ "//lib:jgit-ssh-apache",
"//lib:servlet-api",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 0ce6766..48a5512 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -36,7 +36,6 @@
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.sshd.SshScope.Context;
import com.google.gerrit.util.cli.CmdLineParser;
import com.google.gerrit.util.cli.EndOfOptionsHandler;
@@ -480,7 +479,7 @@
context.getSession().setAccessPath(accessPath);
final Context old = sshScope.set(context);
try {
- context.started = TimeUtil.nowMs();
+ context.start();
thisThread.setName("SSH " + taskName);
try {
diff --git a/java/com/google/gerrit/sshd/SshDaemon.java b/java/com/google/gerrit/sshd/SshDaemon.java
index cd5a511..9ae8660 100644
--- a/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/java/com/google/gerrit/sshd/SshDaemon.java
@@ -37,6 +37,7 @@
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.ssh.HostKey;
import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
import com.google.gerrit.server.ssh.SshInfo;
import com.google.gerrit.server.ssh.SshListenAddresses;
@@ -44,8 +45,6 @@
import com.google.gerrit.server.util.SocketUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.jcraft.jsch.HostKey;
-import com.jcraft.jsch.JSchException;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
@@ -435,12 +434,7 @@
byte[] keyBin = buf.getCompactData();
for (String addr : advertised) {
- try {
- r.add(new HostKey(addr, keyBin));
- } catch (JSchException e) {
- logger.atWarning().log(
- "Cannot format SSHD host key [%s]: %s", pub.getAlgorithm(), e.getMessage());
- }
+ r.add(new HostKey(addr, keyBin));
}
}
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index 2b3052c..616f7d1 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -57,6 +57,9 @@
protected static final String P_STATUS = "status";
protected static final String P_AGENT = "agent";
protected static final String P_MESSAGE = "message";
+ protected static final String P_TOTAL_CPU = "totalCpu";
+ protected static final String P_USER_CPU = "userCpu";
+ protected static final String P_MEMORY = "memory";
private final Provider<SshSession> session;
private final Provider<Context> context;
@@ -171,13 +174,16 @@
void onExecute(DispatchCommand dcmd, int exitValue, SshSession sshSession, String message) {
final Context ctx = context.get();
- ctx.finished = TimeUtil.nowMs();
+ ctx.finish();
String cmd = extractWhat(dcmd);
final LoggingEvent event = log(cmd);
- event.setProperty(P_WAIT, (ctx.started - ctx.created) + "ms");
- event.setProperty(P_EXEC, (ctx.finished - ctx.started) + "ms");
+ event.setProperty(P_WAIT, ctx.getWait() + "ms");
+ event.setProperty(P_EXEC, ctx.getExec() + "ms");
+ event.setProperty(P_TOTAL_CPU, ctx.getTotalCpu() + "ms");
+ event.setProperty(P_USER_CPU, ctx.getUserCpu() + "ms");
+ event.setProperty(P_MEMORY, String.valueOf(ctx.getAllocatedMemory()));
final String status;
switch (exitValue) {
@@ -328,7 +334,7 @@
SshSession session = ctx.getSession();
sessionId = HexFormat.fromInt(session.getSessionId());
currentUser = session.getUser();
- created = ctx.created;
+ created = ctx.getCreated();
}
auditService.dispatch(new SshAuditEvent(sessionId, currentUser, cmd, created, params, result));
}
diff --git a/java/com/google/gerrit/sshd/SshLogJsonLayout.java b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
index 488a4c5..fca0a5a 100644
--- a/java/com/google/gerrit/sshd/SshLogJsonLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
@@ -17,9 +17,12 @@
import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
import static com.google.gerrit.sshd.SshLog.P_AGENT;
import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MEMORY;
import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
import static com.google.gerrit.sshd.SshLog.P_SESSION;
import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_TOTAL_CPU;
+import static com.google.gerrit.sshd.SshLog.P_USER_CPU;
import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
import static com.google.gerrit.sshd.SshLog.P_WAIT;
@@ -44,6 +47,9 @@
public String message;
public String waitTime;
public String execTime;
+ public String totalCpu;
+ public String userCpu;
+ public String memory;
public String status;
public String agent;
public String timeNegotiating;
@@ -67,6 +73,9 @@
this.message = (String) event.getMessage();
this.waitTime = getMdcString(event, P_WAIT);
this.execTime = getMdcString(event, P_EXEC);
+ this.totalCpu = getMdcString(event, P_TOTAL_CPU);
+ this.userCpu = getMdcString(event, P_USER_CPU);
+ this.memory = getMdcString(event, P_MEMORY);
this.status = getMdcString(event, P_STATUS);
this.agent = getMdcString(event, P_AGENT);
diff --git a/java/com/google/gerrit/sshd/SshLogLayout.java b/java/com/google/gerrit/sshd/SshLogLayout.java
index 1dda068..a1f2c40 100644
--- a/java/com/google/gerrit/sshd/SshLogLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogLayout.java
@@ -17,9 +17,12 @@
import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
import static com.google.gerrit.sshd.SshLog.P_AGENT;
import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MEMORY;
import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
import static com.google.gerrit.sshd.SshLog.P_SESSION;
import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_TOTAL_CPU;
+import static com.google.gerrit.sshd.SshLog.P_USER_CPU;
import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
import static com.google.gerrit.sshd.SshLog.P_WAIT;
@@ -56,11 +59,17 @@
buf.append(' ');
buf.append(event.getMessage());
- opt(P_WAIT, buf, event);
- opt(P_EXEC, buf, event);
- opt(P_MESSAGE, buf, event);
- opt(P_STATUS, buf, event);
- opt(P_AGENT, buf, event);
+ String msg = (String) event.getMessage();
+ if (!(msg.startsWith("LOGIN") || msg.equals("LOGOUT"))) {
+ req(P_WAIT, buf, event);
+ req(P_EXEC, buf, event);
+ req(P_MESSAGE, buf, event);
+ req(P_STATUS, buf, event);
+ req(P_AGENT, buf, event);
+ req(P_TOTAL_CPU, buf, event);
+ req(P_USER_CPU, buf, event);
+ req(P_MEMORY, buf, event);
+ }
buf.append('\n');
return buf.toString();
@@ -81,14 +90,6 @@
}
}
- private void opt(String key, StringBuffer buf, LoggingEvent event) {
- Object val = event.getMDC(key);
- if (val != null) {
- buf.append(' ');
- buf.append(val);
- }
- }
-
@Override
public boolean ignoresThrowable() {
return true;
diff --git a/java/com/google/gerrit/sshd/SshScope.java b/java/com/google/gerrit/sshd/SshScope.java
index 340b910..e9ed750 100644
--- a/java/com/google/gerrit/sshd/SshScope.java
+++ b/java/com/google/gerrit/sshd/SshScope.java
@@ -14,6 +14,8 @@
package com.google.gerrit.sshd;
+import com.google.gerrit.metrics.proc.ThreadMXBeanFactory;
+import com.google.gerrit.metrics.proc.ThreadMXBeanInterface;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.RequestCleanup;
@@ -32,21 +34,32 @@
/** Guice scopes for state during an SSH connection. */
public class SshScope {
private static final Key<RequestCleanup> RC_KEY = Key.get(RequestCleanup.class);
+ private static final ThreadMXBeanInterface threadMxBean = ThreadMXBeanFactory.create();
class Context implements RequestContext {
+
private final RequestCleanup cleanup = new RequestCleanup();
private final Map<Key<?>, Object> map = new HashMap<>();
private final SshSession session;
private final String commandLine;
- final long created;
- volatile long started;
- volatile long finished;
+ private final long created;
+ private volatile long started;
+ private volatile long finished;
+ private volatile long startedTotalCpu;
+ private volatile long finishedTotalCpu;
+ private volatile long startedUserCpu;
+ private volatile long finishedUserCpu;
+ private volatile long startedMemory;
+ private volatile long finishedMemory;
private Context(SshSession s, String c, long at) {
session = s;
commandLine = c;
created = started = finished = at;
+ startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+ startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+ startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
map.put(RC_KEY, cleanup);
}
@@ -54,6 +67,50 @@
this(s, c, p.created);
started = p.started;
finished = p.finished;
+ startedTotalCpu = p.startedTotalCpu;
+ finishedTotalCpu = p.finishedTotalCpu;
+ startedUserCpu = p.startedUserCpu;
+ finishedUserCpu = p.finishedUserCpu;
+ startedMemory = p.startedMemory;
+ finishedMemory = p.finishedMemory;
+ }
+
+ void start() {
+ started = TimeUtil.nowMs();
+ startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+ startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+ startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+ }
+
+ void finish() {
+ finished = TimeUtil.nowMs();
+ finishedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+ finishedUserCpu = threadMxBean.getCurrentThreadUserTime();
+ finishedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+ }
+
+ public long getCreated() {
+ return created;
+ }
+
+ public long getWait() {
+ return started - created;
+ }
+
+ public long getExec() {
+ return finished - started;
+ }
+
+ public long getTotalCpu() {
+ return (finishedTotalCpu - startedTotalCpu) / 1_000_000;
+ }
+
+ public long getUserCpu() {
+ return (finishedUserCpu - startedUserCpu) / 1_000_000;
+ }
+
+ public long getAllocatedMemory() {
+ return finishedMemory - startedMemory;
}
String getCommandLine() {
diff --git a/java/com/google/gerrit/sshd/SshSessionFactoryInitializer.java b/java/com/google/gerrit/sshd/SshSessionFactoryInitializer.java
new file mode 100644
index 0000000..1cdf923
--- /dev/null
+++ b/java/com/google/gerrit/sshd/SshSessionFactoryInitializer.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.sshd;
+
+import static com.google.gerrit.server.config.SshClientImplementation.APACHE;
+
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.sshd.DefaultProxyDataFactory;
+import org.eclipse.jgit.transport.sshd.JGitKeyCache;
+import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
+import org.eclipse.jgit.util.FS;
+
+public class SshSessionFactoryInitializer {
+ public static void init(Config config) {
+ if (APACHE == config.getEnum("ssh", null, "clientImplementation", APACHE)) {
+ SshdSessionFactory factory =
+ new SshdSessionFactory(new JGitKeyCache(), new DefaultProxyDataFactory());
+ factory.setHomeDirectory(FS.DETECTED.userHome());
+ SshSessionFactory.setInstance(factory);
+ }
+ }
+
+ private SshSessionFactoryInitializer() {}
+}
diff --git a/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java b/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
index f2ab4e8..e2d554d 100644
--- a/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
+++ b/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
@@ -143,7 +143,7 @@
name = "--branch",
aliases = {"-b"},
metaVar = "BRANCH",
- usage = "initial branch name\n(default: master)")
+ usage = "initial branch name\n(default: gerrit.defaultProject)")
private List<String> branch;
@Option(name = "--empty-commit", usage = "to create initial empty commit")
diff --git a/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java b/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
index 7bf42eb..35699af 100644
--- a/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
+++ b/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
@@ -19,10 +19,10 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.ioutil.ColumnFormatter;
import com.google.gerrit.server.restapi.group.ListGroups;
import com.google.gerrit.sshd.CommandMetaData;
diff --git a/java/com/google/gerrit/sshd/commands/ListMembersCommand.java b/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
index 52d0468..45c6a35 100644
--- a/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
+++ b/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
@@ -19,12 +19,12 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.server.DynamicOptions;
import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.ioutil.ColumnFormatter;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.restapi.group.ListMembers;
diff --git a/java/com/google/gerrit/sshd/commands/SetMembersCommand.java b/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
index db8e42a..f788f14 100644
--- a/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
@@ -21,6 +21,7 @@
import com.google.common.collect.Streams;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -28,7 +29,6 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.group.GroupResource;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.restapi.group.AddMembers;
import com.google.gerrit.server.restapi.group.AddSubgroups;
import com.google.gerrit.server.restapi.group.DeleteMembers;
diff --git a/java/com/google/gerrit/testing/TestLoggingActivator.java b/java/com/google/gerrit/testing/TestLoggingActivator.java
index a766429..b3ad862 100644
--- a/java/com/google/gerrit/testing/TestLoggingActivator.java
+++ b/java/com/google/gerrit/testing/TestLoggingActivator.java
@@ -31,6 +31,7 @@
// Silence non-critical messages from MINA SSHD.
.put("org.apache.mina", Level.WARN)
+ .put("org.apache.sshd.client", Level.WARN)
.put("org.apache.sshd.common", Level.WARN)
.put("org.apache.sshd.server", Level.WARN)
.put("org.apache.sshd.common.keyprovider.FileKeyPairProvider", Level.INFO)
@@ -47,11 +48,6 @@
.put("org.openid4java.server.RealmVerifier", Level.ERROR)
.put("org.openid4java.message.AuthSuccess", Level.ERROR)
- // Silence non-critical messages from c3p0 (if used).
- .put("com.mchange.v2.c3p0", Level.WARN)
- .put("com.mchange.v2.resourcepool", Level.WARN)
- .put("com.mchange.v2.sql", Level.WARN)
-
// Silence non-critical messages from apache.http.
.put("org.apache.http", Level.WARN)
@@ -61,6 +57,8 @@
// Silence non-critical messages from JGit.
.put("org.eclipse.jgit.transport.PacketLineIn", Level.WARN)
.put("org.eclipse.jgit.transport.PacketLineOut", Level.WARN)
+ .put("org.eclipse.jgit.internal.transport.sshd", Level.WARN)
+ .put("org.eclipse.jgit.util.FileUtils", Level.WARN)
.put("org.eclipse.jgit.internal.storage.file.FileSnapshot", Level.WARN)
.put("org.eclipse.jgit.util.FS", Level.WARN)
.put("org.eclipse.jgit.util.SystemReader", Level.WARN)
diff --git a/java/gerrit/PRED_commit_delta_4.java b/java/gerrit/PRED_commit_delta_4.java
index 6e971fc..502b15b 100644
--- a/java/gerrit/PRED_commit_delta_4.java
+++ b/java/gerrit/PRED_commit_delta_4.java
@@ -14,11 +14,10 @@
package gerrit;
-import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
+import com.googlecode.prolog_cafe.exceptions.JavaException;
import com.googlecode.prolog_cafe.exceptions.PInstantiationException;
import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
@@ -28,8 +27,15 @@
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
import com.googlecode.prolog_cafe.lang.VariableTerm;
+import java.io.IOException;
import java.util.Iterator;
+import java.util.List;
import java.util.regex.Pattern;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.io.DisabledOutputStream;
/**
* Given a regular expression, checks it against the file list in the most recent patchset of a
@@ -76,10 +82,22 @@
engine.r3 = arg3;
engine.r4 = arg4;
- PatchList pl = StoredValues.PATCH_LIST.get(engine);
- Iterator<PatchListEntry> iter = pl.getPatches().iterator();
+ Repository repository = StoredValues.REPOSITORY.get(engine);
- engine.r5 = new JavaObjectTerm(iter);
+ try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) {
+ diffFormatter.setRepository(repository);
+ // Do not detect renames; that would require reading file contents, which is slow for large
+ // files.
+ RevCommit commit = StoredValues.COMMIT.get(engine);
+ List<DiffEntry> diffEntries =
+ diffFormatter.scan(
+ // In case of a merge commit, i.e. >1 parents, we use parent #0 by convention. So
+ // parent #0 is always the right choice, if it exists.
+ commit.getParentCount() > 0 ? commit.getParent(0) : null, commit);
+ engine.r5 = new JavaObjectTerm(diffEntries.iterator());
+ } catch (IOException e) {
+ throw new JavaException(e);
+ }
return engine.jtry5(commit_delta_check, commit_delta_next);
}
@@ -95,23 +113,22 @@
Pattern regex = (Pattern) ((JavaObjectTerm) a1).object();
@SuppressWarnings("unchecked")
- Iterator<PatchListEntry> iter = (Iterator<PatchListEntry>) ((JavaObjectTerm) a5).object();
+ Iterator<DiffEntry> iter = (Iterator<DiffEntry>) ((JavaObjectTerm) a5).object();
while (iter.hasNext()) {
- PatchListEntry patch = iter.next();
- String newName = patch.getNewName();
- String oldName = patch.getOldName();
- Patch.ChangeType changeType = patch.getChangeType();
+ DiffEntry diffEntry = iter.next();
+ String newName = diffEntry.getNewPath();
+ String oldName = diffEntry.getOldPath();
+ DiffEntry.ChangeType changeType = diffEntry.getChangeType();
- if (Patch.isMagic(newName)) {
- continue;
- }
-
- if (regex.matcher(newName).find() || (oldName != null && regex.matcher(oldName).find())) {
+ if ((!isNull(newName) && regex.matcher(newName).find())
+ || (!isNull(oldName) && regex.matcher(oldName).find())) {
SymbolTerm changeSym = getTypeSymbol(changeType);
- SymbolTerm newSym = SymbolTerm.create(newName);
- SymbolTerm oldSym = Prolog.Nil;
- if (oldName != null) {
- oldSym = SymbolTerm.create(oldName);
+ SymbolTerm newSym = isNull(newName) ? Prolog.Nil : SymbolTerm.create(newName);
+ SymbolTerm oldSym = isNull(oldName) ? Prolog.Nil : SymbolTerm.create(oldName);
+ // For compatibility with legacy semantics:
+ if (changeSym.equals(delete)) {
+ newSym = oldSym;
+ oldSym = Prolog.Nil;
}
if (!a2.unify(changeSym, engine.trail)) {
@@ -130,6 +147,10 @@
}
}
+ private static boolean isNull(String path) {
+ return path.equals("/dev/null");
+ }
+
private static final class PRED_commit_delta_next extends Operation {
@Override
public Operation exec(Prolog engine) {
@@ -152,20 +173,18 @@
}
}
- private static SymbolTerm getTypeSymbol(Patch.ChangeType type) {
+ private static SymbolTerm getTypeSymbol(DiffEntry.ChangeType type) {
switch (type) {
- case ADDED:
+ case ADD:
return add;
- case MODIFIED:
+ case MODIFY:
return modify;
- case DELETED:
+ case DELETE:
return delete;
- case RENAMED:
+ case RENAME:
return rename;
- case COPIED:
+ case COPY:
return copy;
- case REWRITE:
- break;
}
throw new IllegalArgumentException("ChangeType not recognized");
}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 1b55652..7495e63 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -75,6 +75,7 @@
import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.acceptance.testsuite.request.SshSessionFactory;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.entities.AccessSection;
@@ -150,9 +151,9 @@
import com.google.gerrit.truth.NullAwareCorrespondence;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import com.jcraft.jsch.KeyPair;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -2001,7 +2002,7 @@
// Add a new key
sender.clear();
- String newKey = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email());
+ String newKey = TestSshKeys.publicKey(SshSessionFactory.genSshKey(), admin.email());
gApi.accounts().self().addSshKey(newKey);
info = gApi.accounts().self().listSshKeys();
assertThat(info).hasSize(2);
@@ -2023,7 +2024,7 @@
// Add another new key
sender.clear();
- String newKey2 = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email());
+ String newKey2 = TestSshKeys.publicKey(SshSessionFactory.genSshKey(), admin.email());
gApi.accounts().self().addSshKey(newKey2);
info = gApi.accounts().self().listSshKeys();
assertThat(info).hasSize(3);
@@ -2074,7 +2075,7 @@
// Add a new key
sender.clear();
- String newKey = TestSshKeys.publicKey(TestSshKeys.genSshKey(), user.email());
+ String newKey = TestSshKeys.publicKey(SshSessionFactory.genSshKey(), user.email());
gApi.accounts().id(user.username()).addSshKey(newKey);
info = gApi.accounts().id(user.username()).listSshKeys();
assertThat(info).hasSize(2);
@@ -2103,7 +2104,7 @@
@Test
@UseSsh
public void userCannotAddSshKeyToOtherAccount() throws Exception {
- String newKey = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email());
+ String newKey = TestSshKeys.publicKey(SshSessionFactory.genSshKey(), admin.email());
requestScopeOperations.setApiUser(user.id());
assertThrows(AuthException.class, () -> gApi.accounts().id(admin.username()).addSshKey(newKey));
}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
index 4c3c77f..5279ba1 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
@@ -32,6 +32,7 @@
import com.google.gerrit.entities.BooleanProjectConfig;
import com.google.gerrit.entities.ContributorAgreement;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.PermissionRule;
import com.google.gerrit.extensions.api.changes.CherryPickInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
@@ -49,7 +50,6 @@
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.testing.ConfigSuite;
import com.google.inject.Inject;
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 50b7a7c..517cf89 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -702,6 +702,8 @@
@Test
public void reviewWithReadyByNonOwnerReturnsError() throws Exception {
PushOneCommit.Result r = createChange();
+ change(r).setWorkInProgress();
+
ReviewInput in = ReviewInput.noScore().setReady(true);
requestScopeOperations.setApiUser(user.id());
AuthException thrown =
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
index eb5b9b0..4448e87 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
@@ -24,6 +24,7 @@
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.SubmitRequirementInfo;
import com.google.gerrit.extensions.config.FactoryModule;
@@ -35,6 +36,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
public class ChangeSubmitRequirementIT extends AbstractDaemonTest {
@@ -55,7 +57,7 @@
};
}
- @Inject CustomSubmitRule rule;
+ @Inject private CustomSubmitRule rule;
@Test
public void submitRequirementIsPropagated() throws Exception {
@@ -167,6 +169,35 @@
assertThat(result.get(0).changeId).isEqualTo(change.info().changeId);
}
+ @Test
+ public void submitRuleIsInvokedOnlyOnceWhenGettingChangeDetails() throws Exception {
+ PushOneCommit.Result r = createChange("Some Change", "foo.txt", "some content");
+ String changeId = r.getChangeId();
+
+ rule.numberOfEvaluations.set(0);
+ gApi.changes()
+ .id(changeId)
+ .get(ListChangesOption.ALL_REVISIONS, ListChangesOption.CURRENT_ACTIONS);
+
+ // Submit rules are computed freshly, but only once.
+ assertThat(rule.numberOfEvaluations.get()).isEqualTo(1);
+ }
+
+ @Test
+ public void submitRuleIsNotInvokedWhenQueryingChange() throws Exception {
+ PushOneCommit.Result r = createChange("Some Change", "foo.txt", "some content");
+ String changeId = r.getChangeId();
+
+ rule.numberOfEvaluations.set(0);
+ gApi.changes()
+ .query(changeId)
+ .withOptions(ListChangesOption.ALL_REVISIONS, ListChangesOption.CURRENT_ACTIONS)
+ .get();
+
+ // Submit rule evaluation results from the change index are reused
+ assertThat(rule.numberOfEvaluations.get()).isEqualTo(0);
+ }
+
private List<ChangeInfo> queryIsSubmittable() throws Exception {
return gApi.changes().query("is:submittable project:" + project.get()).get();
}
@@ -186,6 +217,7 @@
@Singleton
private static class CustomSubmitRule implements SubmitRule {
private Optional<SubmitRecord.Status> recordStatus = Optional.empty();
+ private AtomicInteger numberOfEvaluations = new AtomicInteger();
public void block(boolean block) {
this.status(block ? Optional.of(SubmitRecord.Status.NOT_READY) : Optional.empty());
@@ -197,6 +229,7 @@
@Override
public Optional<SubmitRecord> evaluate(ChangeData changeData) {
+ numberOfEvaluations.incrementAndGet();
if (this.recordStatus.isPresent()) {
SubmitRecord record = new SubmitRecord();
record.labels = new ArrayList<>();
diff --git a/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java b/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
index c8b1715..34679bd 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
@@ -40,6 +40,7 @@
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
@@ -60,8 +61,10 @@
import com.google.gerrit.extensions.validators.CommentValidator;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.restapi.change.OnPostReview;
import com.google.gerrit.server.restapi.change.PostReview;
+import com.google.gerrit.server.rules.SubmitRule;
import com.google.gerrit.server.update.CommentsRejectedException;
import com.google.gerrit.testing.TestCommentHelper;
import com.google.inject.Inject;
@@ -677,6 +680,19 @@
}
}
+ @Test
+ public void submitRulesAreInvokedOnlyOnce() throws Exception {
+ PushOneCommit.Result r = createChange();
+
+ TestSubmitRule testSubmitRule = new TestSubmitRule();
+ try (Registration registration = extensionRegistry.newRegistration().add(testSubmitRule)) {
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 1);
+ gApi.changes().id(r.getChangeId()).current().review(input);
+ }
+
+ assertThat(testSubmitRule.count).isEqualTo(1);
+ }
+
private static class TestListener implements CommentAddedListener {
public CommentAddedListener.Event lastCommentAddedEvent;
@@ -753,4 +769,14 @@
assertThat(approvals).containsExactly(labelName, (short) expectedNewValue);
}
}
+
+ private static class TestSubmitRule implements SubmitRule {
+ int count;
+
+ @Override
+ public Optional<SubmitRecord> evaluate(ChangeData changeData) {
+ count++;
+ return Optional.empty();
+ }
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
new file mode 100644
index 0000000..bc9f50a5
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
@@ -0,0 +1,103 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.api.change;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.entities.LabelFunction;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.LabelValue;
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.server.project.SubmitRuleEvaluator;
+import com.google.gerrit.server.project.SubmitRuleOptions;
+import com.google.inject.Inject;
+import java.util.List;
+import org.junit.Test;
+
+public class SubmitRuleIT extends AbstractDaemonTest {
+ @Inject private SubmitRuleEvaluator.Factory submitRuleEvaluatorFactory;
+
+ @Test
+ public void submitRecordsForClosedChanges_parsedBackByDefault() throws Exception {
+ SubmitRuleEvaluator submitRuleEvaluator =
+ submitRuleEvaluatorFactory.create(SubmitRuleOptions.defaults());
+ PushOneCommit.Result r = createChange();
+ approve(r.getChangeId());
+ List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ gApi.changes().id(r.getChangeId()).current().submit();
+ // Add a new label that blocks submission if not granted. In case we reevaluate the rules,
+ // this would show up as blocking submission.
+ setupCustomBlockingLabel();
+ List<SubmitRecord> recordsAfterSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ recordsBeforeSubmission.forEach(
+ sr -> sr.status = SubmitRecord.Status.CLOSED); // Set status to closed
+ assertThat(recordsBeforeSubmission).isEqualTo(recordsAfterSubmission);
+ }
+
+ @Test
+ public void submitRecordsForClosedChanges_recomputedIfRequested() throws Exception {
+ SubmitRuleEvaluator submitRuleEvaluator =
+ submitRuleEvaluatorFactory.create(
+ SubmitRuleOptions.builder().recomputeOnClosedChanges(true).build());
+ PushOneCommit.Result r = createChange();
+ approve(r.getChangeId());
+ List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ gApi.changes().id(r.getChangeId()).current().submit();
+ // Add a new label that blocks submission if not granted. In case we reevaluate the rules,
+ // this would show up as blocking submission.
+ setupCustomBlockingLabel();
+ List<SubmitRecord> recordsAfterSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ assertThat(recordsBeforeSubmission).isNotEqualTo(recordsAfterSubmission);
+ assertThat(recordsAfterSubmission).hasSize(1);
+ List<SubmitRecord.Label> recordLabels = recordsAfterSubmission.get(0).labels;
+
+ assertThat(recordLabels).hasSize(2);
+ assertCodeReviewApproved(recordLabels);
+ assertMyLabelNeed(recordLabels);
+ }
+
+ private void assertCodeReviewApproved(List<SubmitRecord.Label> recordLabels) {
+ SubmitRecord.Label haveCodeReview = new SubmitRecord.Label();
+ haveCodeReview.label = "Code-Review";
+ haveCodeReview.status = SubmitRecord.Label.Status.OK;
+ haveCodeReview.appliedBy = admin.id();
+ assertThat(recordLabels).contains(haveCodeReview);
+ }
+
+ private void assertMyLabelNeed(List<SubmitRecord.Label> recordLabels) {
+ SubmitRecord.Label needCustomLabel = new SubmitRecord.Label();
+ needCustomLabel.label = "My-Label";
+ needCustomLabel.status = SubmitRecord.Label.Status.NEED;
+ assertThat(recordLabels).contains(needCustomLabel);
+ }
+
+ private void setupCustomBlockingLabel() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .upsertLabelType(
+ LabelType.builder(
+ "My-Label",
+ ImmutableList.of(
+ LabelValue.create((short) 0, "Not approved"),
+ LabelValue.create((short) 1, "Approved")))
+ .setFunction(LabelFunction.MAX_WITH_BLOCK)
+ .build());
+ u.save();
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/group/BUILD b/javatests/com/google/gerrit/acceptance/api/group/BUILD
index 5d7dea1..29f532e 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/BUILD
+++ b/javatests/com/google/gerrit/acceptance/api/group/BUILD
@@ -20,8 +20,8 @@
name = "util",
srcs = ["GroupAssert.java"],
deps = [
+ "//java/com/google/gerrit/entities",
"//java/com/google/gerrit/extensions:api",
- "//java/com/google/gerrit/server",
"//lib/truth",
],
)
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupAssert.java b/javatests/com/google/gerrit/acceptance/api/group/GroupAssert.java
index dd891ce..079d43e9 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupAssert.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupAssert.java
@@ -17,9 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.server.group.InternalGroup;
import java.util.Set;
public class GroupAssert {
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupIndexerIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupIndexerIT.java
index 41ae370..87bdee4 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupIndexerIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupIndexerIT.java
@@ -21,13 +21,13 @@
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.exceptions.NoSuchGroupException;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.group.db.InternalGroupUpdate;
import com.google.gerrit.server.group.testing.InternalGroupSubject;
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index fcd6b76..a277f26 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -60,6 +60,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
@@ -88,7 +89,6 @@
import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.account.GroupsSnapshotReader;
import com.google.gerrit.server.account.ServiceUserClassifier;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.PeriodicGroupIndexer;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.group.db.Groups;
diff --git a/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java b/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
index 6838f8d..18eca27 100644
--- a/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
@@ -48,18 +48,14 @@
@NoHttpd
public class PluginIT extends AbstractDaemonTest {
private static final String JS_PLUGIN = "Gerrit.install(function(self){});\n";
- private static final String HTML_PLUGIN =
- String.format("<dom-module id=\"test\"><script>%s</script></dom-module>", JS_PLUGIN);
private static final RawInput JS_PLUGIN_CONTENT = RawInputUtil.create(JS_PLUGIN.getBytes(UTF_8));
- private static final RawInput HTML_PLUGIN_CONTENT =
- RawInputUtil.create(HTML_PLUGIN.getBytes(UTF_8));
private static final ImmutableList<String> PLUGINS =
ImmutableList.of(
"plugin-a.js",
- "plugin-b.html",
+ "plugin-b.js",
"plugin-c.js",
- "plugin-d.html",
+ "plugin-d.js",
"plugin-normal.jar",
"plugin-empty.jar",
"plugin-unset.jar",
@@ -97,7 +93,7 @@
assertPlugins(list().start(1).limit(2).get(), PLUGINS.subList(1, 3));
// With prefix
- assertPlugins(list().prefix("plugin-b").get(), ImmutableList.of("plugin-b.html"));
+ assertPlugins(list().prefix("plugin-b").get(), ImmutableList.of("plugin-b.js"));
assertPlugins(list().prefix("PLUGIN-").get(), ImmutableList.of());
// With substring
@@ -105,7 +101,7 @@
assertPlugins(list().substring("lugin-").start(1).limit(2).get(), PLUGINS.subList(1, 3));
// With regex
- assertPlugins(list().regex(".*in-b").get(), ImmutableList.of("plugin-b.html"));
+ assertPlugins(list().regex(".*in-b").get(), ImmutableList.of("plugin-b.js"));
assertPlugins(list().regex("plugin-.*").get(), PLUGINS.subList(0, PLUGINS.size() - 1));
assertPlugins(list().regex("plugin-.*").start(1).limit(2).get(), PLUGINS.subList(1, 3));
@@ -147,7 +143,7 @@
com.google.gerrit.extensions.common.InstallPluginInput input =
new com.google.gerrit.extensions.common.InstallPluginInput();
input.raw = JS_PLUGIN_CONTENT;
- gApi.plugins().install("legacy.html", input);
+ gApi.plugins().install("legacy.js", input);
gApi.plugins().name("legacy").get();
}
@@ -198,9 +194,6 @@
if (plugin.endsWith(".js")) {
return JS_PLUGIN_CONTENT;
}
- if (plugin.endsWith(".html")) {
- return HTML_PLUGIN_CONTENT;
- }
assertThat(plugin).endsWith(".jar");
return pluginJarContent(plugin);
}
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 6e19ac2..dd70d4a 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -116,7 +116,7 @@
extensionRegistry.newRegistration().add(projectIndexedCounter)) {
String name = name("foo");
assertThat(gApi.projects().create(name).get().name).isEqualTo(name);
-
+ assertHead(name, "refs/heads/master");
RevCommit head = getRemoteHead(name, RefNames.REFS_CONFIG);
eventRecorder.assertRefUpdatedEvents(name, RefNames.REFS_CONFIG, null, head);
@@ -126,6 +126,23 @@
}
@Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "main")
+ public void createProject_WhenDefaultBranchIsSetInConfig() throws Exception {
+ ProjectIndexedCounter projectIndexedCounter = new ProjectIndexedCounter();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectIndexedCounter)) {
+ String name = name("foo");
+ assertThat(gApi.projects().create(name).get().name).isEqualTo(name);
+ assertHead(name, "refs/heads/main");
+ RevCommit head = getRemoteHead(name, RefNames.REFS_CONFIG);
+ eventRecorder.assertRefUpdatedEvents(name, RefNames.REFS_CONFIG, null, head);
+
+ eventRecorder.assertRefUpdatedEvents(name, "refs/heads/main", new String[] {});
+ projectIndexedCounter.assertReindexOf(name);
+ }
+ }
+
+ @Test
public void createProjectWithInitialBranches() throws Exception {
ProjectIndexedCounter projectIndexedCounter = new ProjectIndexedCounter();
try (Registration registration =
@@ -135,12 +152,13 @@
ProjectInput input = new ProjectInput();
input.name = name;
input.createEmptyCommit = true;
- input.branches = ImmutableList.of("master", "foo");
+ input.branches = ImmutableList.of("foo", "master");
assertThat(gApi.projects().create(input).get().name).isEqualTo(name);
assertThat(
gApi.projects().name(name).branches().get().stream().map(b -> b.ref).collect(toSet()))
.containsExactly("refs/heads/foo", "refs/heads/master", "HEAD", RefNames.REFS_CONFIG);
+ assertHead(name, "refs/heads/foo");
RevCommit head = getRemoteHead(name, RefNames.REFS_CONFIG);
eventRecorder.assertRefUpdatedEvents(name, RefNames.REFS_CONFIG, null, head);
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index 68bb66c..0b18503 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -76,7 +76,8 @@
private static final String FILE_CONTENT2 = "1st line\n2nd line\n3rd line\n";
private boolean intraline;
- private boolean useNewDiffCache;
+ private boolean useNewDiffCacheListFiles;
+ private boolean useNewDiffCacheGetDiff;
private ObjectId commit1;
private String changeId;
@@ -90,7 +91,10 @@
baseConfig.setString("cache", "diff_intraline", "timeout", "1 minute");
intraline = baseConfig.getBoolean(TEST_PARAMETER_MARKER, "intraline", false);
- useNewDiffCache = baseConfig.getBoolean("cache", "diff_cache", "useNewDiffCache", false);
+ useNewDiffCacheListFiles =
+ baseConfig.getBoolean("cache", "diff_cache", "runNewDiffCache_ListFiles", false);
+ useNewDiffCacheGetDiff =
+ baseConfig.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
ObjectId headCommit = testRepo.getRepository().resolve("HEAD");
commit1 =
@@ -516,6 +520,32 @@
}
@Test
+ public void diffAgainstAutoMergeCanBeRetrievedForCommitMessageAndMergeList() throws Exception {
+ PushOneCommit.Result result = createMergeCommitChange("refs/for/master", "my_file.txt");
+ String changeId = result.getChangeId();
+ addModifiedPatchSet(changeId, "my_file.txt", content -> content.concat("Line I\nLine II\n"));
+
+ DiffInfo commitMessageDiffInfo =
+ getDiffRequest(changeId, CURRENT, COMMIT_MSG)
+ .get(); // diff latest PS against base (auto-merge)
+ DiffInfo mergeListDiffInfo =
+ getDiffRequest(changeId, CURRENT, MERGE_LIST)
+ .get(); // diff latest PS against base (auto-merge)
+
+ assertThat(commitMessageDiffInfo).changeType().isEqualTo(ChangeType.ADDED);
+ assertThat(commitMessageDiffInfo).content().hasSize(1);
+
+ assertThat(mergeListDiffInfo).changeType().isEqualTo(ChangeType.ADDED);
+ assertThat(mergeListDiffInfo).content().hasSize(1);
+ assertThat(mergeListDiffInfo)
+ .content()
+ .element(0)
+ .linesOfB()
+ .element(0)
+ .isEqualTo("Merge List:");
+ }
+
+ @Test
public void diffOfUnmodifiedFileMarksAllLinesAsCommon() throws Exception {
String filePath = "a_new_file.txt";
String fileContent = "Line 1\nLine 2\nLine 3\n";
@@ -1273,7 +1303,7 @@
public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase_WhenEquallyModifiedInBoth()
throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
- assume().that(useNewDiffCache).isFalse();
+ assume().that(useNewDiffCacheListFiles).isFalse();
Function<String, String> contentModification =
fileContent -> fileContent.replace("1st line\n", "First line\n");
@@ -1366,7 +1396,7 @@
@Test
public void filesTouchedByPatchSetsAndContainingOnlyRebaseHunksAreIgnored() throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
- assume().that(useNewDiffCache).isFalse();
+ assume().that(useNewDiffCacheListFiles).isFalse();
addModifiedPatchSet(
changeId, FILE_NAME, fileContent -> fileContent.replace("Line 50\n", "Line fifty\n"));
@@ -2748,7 +2778,8 @@
@Test
public void symlinkConvertedToRegularFileIsIdentifiedAsAdded() throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
- assume().that(useNewDiffCache).isFalse();
+ assume().that(useNewDiffCacheListFiles).isFalse();
+ assume().that(useNewDiffCacheGetDiff).isFalse();
String target = "file.txt";
String symlink = "link.lnk";
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java
new file mode 100644
index 0000000..46954e98
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java
@@ -0,0 +1,32 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.api.revision;
+
+import com.google.gerrit.testing.ConfigSuite;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * Runs the {@link RevisionDiffIT} tests with the new diff cache, enabled for the single file "Get
+ * Diff" endpoint. This is temporary until the new diff cache is fully deployed. The new diff cache
+ * will become the default in the future.
+ */
+public class RevisionNewDiffCacheForSingleFileIT extends RevisionDiffIT {
+ @ConfigSuite.Default
+ public static Config newDiffCacheConfig() {
+ Config config = new Config();
+ config.setBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", true);
+ return config;
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
index 4b85c30..ec0bcc6 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
@@ -18,14 +18,15 @@
import org.eclipse.jgit.lib.Config;
/**
- * Runs the {@link RevisionDiffIT} tests with the new diff cache. This is temporary until the new
- * diff cache is fully deployed. The new diff cache will become the default in the future.
+ * Runs the {@link RevisionDiffIT} with the list files endpoint using the new diff cache. This is
+ * temporary until the new diff cache is fully deployed. The new diff cache will become the default
+ * in the future.
*/
public class RevisionNewDiffCacheIT extends RevisionDiffIT {
@ConfigSuite.Default
public static Config newDiffCacheConfig() {
Config config = new Config();
- config.setBoolean("cache", "diff_cache", "useNewDiffCache", true);
+ config.setBoolean("cache", "diff_cache", "runNewDiffCache_ListFiles", true);
return config;
}
}
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 845c461..eac0f1b 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -62,6 +62,7 @@
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.Address;
@@ -100,6 +101,7 @@
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.receive.NoteDbPushOption;
+import com.google.gerrit.server.git.receive.PluginPushOption;
import com.google.gerrit.server.git.receive.ReceiveConstants;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
@@ -2364,6 +2366,8 @@
private final AtomicInteger count = new AtomicInteger();
private final boolean validateAll;
+ @Nullable private CommitReceivedEvent receivedEvent;
+
TestValidator(boolean validateAll) {
this.validateAll = validateAll;
}
@@ -2373,7 +2377,8 @@
}
@Override
- public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent) {
+ public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receivedEvent) {
+ this.receivedEvent = receivedEvent;
count.incrementAndGet();
return Collections.emptyList();
}
@@ -2386,6 +2391,31 @@
public int count() {
return count.get();
}
+
+ @Nullable
+ public CommitReceivedEvent getReceivedEvent() {
+ return receivedEvent;
+ }
+ }
+
+ private static class TestPluginPushOption implements PluginPushOption {
+ private final String name;
+ private final String description;
+
+ TestPluginPushOption(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
}
private static class TopicValidator implements TopicEditedListener {
@@ -2449,6 +2479,38 @@
}
@Test
+ public void pushOptionsArePassedToCommitValidationListener() throws Exception {
+ TestValidator validator = new TestValidator();
+ PluginPushOption fooOption = new TestPluginPushOption("foo", "some description");
+ PluginPushOption barOption = new TestPluginPushOption("bar", "other description");
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(validator).add(fooOption).add(barOption)) {
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "change2", "b.txt", "content");
+ push.setPushOptions(ImmutableList.of("trace=123", "gerrit~foo", "gerrit~bar=456"));
+ PushOneCommit.Result r = push.to("refs/for/master");
+ r.assertOkStatus();
+ assertThat(validator.getReceivedEvent().pushOptions)
+ .containsExactly("trace", "123", "gerrit~foo", "", "gerrit~bar", "456");
+ }
+ }
+
+ @Test
+ public void pluginPushOptionsHelp() throws Exception {
+ PluginPushOption fooOption = new TestPluginPushOption("foo", "some description");
+ PluginPushOption barOption = new TestPluginPushOption("bar", "other description");
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(fooOption).add(barOption)) {
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "change2", "b.txt", "content");
+ push.setPushOptions(ImmutableList.of("help"));
+ PushOneCommit.Result r = push.to("refs/for/master");
+ r.assertErrorStatus("see help");
+ r.assertMessage("-o gerrit~bar: other description\n-o gerrit~foo: some description\n");
+ }
+ }
+
+ @Test
public void pushNoteDbRef() throws Exception {
String ref = "refs/changes/34/1234/meta";
RevCommit c = testRepo.commit().message("Junk NoteDb commit").create();
diff --git a/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java b/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java
new file mode 100644
index 0000000..b16394d
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java
@@ -0,0 +1,208 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.git;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.eclipse.jgit.lib.Constants.HEAD;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.common.RawInputUtil;
+import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.extensions.common.MergeInput;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Ensures that auto merge commits are created when a new patch set or change is uploaded. */
+public class AutoMergeIT extends AbstractDaemonTest {
+ private RevCommit parent1;
+ private RevCommit parent2;
+
+ @Before
+ public void setup() throws Exception {
+ ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
+
+ PushOneCommit.Result p1 =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ "parent 1",
+ ImmutableMap.of("foo", "foo-1.2", "bar", "bar-1.2"))
+ .to("refs/for/master");
+ parent1 = p1.getCommit();
+
+ // reset HEAD in order to create a sibling of the first change
+ testRepo.reset(initial);
+
+ PushOneCommit.Result p2 =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ "parent 2",
+ ImmutableMap.of("foo", "foo-2.2", "bar", "bar-2.2"))
+ .to("refs/for/master");
+ parent2 = p2.getCommit();
+ }
+
+ @Test
+ public void autoMergeCreatedWhenPushingNewChange() throws Exception {
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1, parent2));
+ PushOneCommit.Result result = m.to("refs/for/master");
+ result.assertOkStatus();
+ assertAutoMergeCreated(result.getCommit());
+ }
+
+ @Test
+ public void autoMergeCreatedWhenPushingNewPatchSet() throws Exception {
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1, parent2));
+ PushOneCommit.Result ps1 = m.to("refs/for/master");
+ RevCommit ps2 =
+ testRepo
+ .amend(ps1.getCommit())
+ .message("PS2")
+ .insertChangeId(ps1.getChangeId().substring(1))
+ .create();
+ testRepo.reset(ps2);
+ GitUtil.pushHead(testRepo, "refs/for/master");
+ // Make sure we have two patch sets
+ assertThat(ps2.getParents().length).isEqualTo(2);
+ assertThat(gApi.changes().id(ps1.getChangeId()).get().revisions.size()).isEqualTo(2);
+ assertAutoMergeCreated(ps2);
+ }
+
+ @Test
+ public void autoMergeCreatedWhenChangeCreatedOnApi() throws Exception {
+ ChangeInput ci = new ChangeInput(project.get(), "master", "Merge commit");
+ ci.merge = new MergeInput();
+ ci.merge.source = parent1.name();
+
+ String newChangePatchSetSha1 = gApi.changes().create(ci).get().currentRevision;
+ assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
+ }
+
+ @Test
+ public void autoMergeCreatedWhenNewPatchSetCreatedOnApi() throws Exception {
+ ChangeInput ci = new ChangeInput(project.get(), "master", "Merge commit");
+ ci.merge = new MergeInput();
+ ci.merge.source = parent1.name();
+
+ String changeId = gApi.changes().create(ci).get().changeId;
+ gApi.changes().id(changeId).setMessage("New Commit Message\n\nChange-Id: " + changeId);
+ assertThat(gApi.changes().id(changeId).get().revisions.size()).isEqualTo(2);
+ String newChangePatchSetSha1 = gApi.changes().id(changeId).get().currentRevision;
+ assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
+ }
+
+ @Test
+ public void autoMergeCreatedWhenChangeEditIsPublished() throws Exception {
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1, parent2));
+ PushOneCommit.Result result = m.to("refs/for/master");
+ result.assertOkStatus();
+ assertAutoMergeCreated(result.getCommit());
+
+ gApi.changes()
+ .id(result.getChangeId())
+ .edit()
+ .modifyFile("new-file", RawInputUtil.create("content"));
+ gApi.changes().id(result.getChangeId()).edit().publish();
+ assertThat(gApi.changes().id(result.getChangeId()).get().revisions.size()).isEqualTo(2);
+ String newChangePatchSetSha1 = gApi.changes().id(result.getChangeId()).get().currentRevision;
+ assertAutoMergeCreated(ObjectId.fromString(newChangePatchSetSha1));
+ }
+
+ @Test
+ public void noAutoMergeCreatedWhenPushingNonMergeCommit() throws Exception {
+ PushOneCommit.Result change = createChange();
+ change.assertOkStatus();
+ assertNoAutoMergeCreated(change.getCommit());
+ }
+
+ @Test
+ public void autoMergeComputedInMemoryWhenMissing() throws Exception {
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1, parent2));
+ PushOneCommit.Result result = m.to("refs/for/master");
+ result.assertOkStatus();
+ assertAutoMergeCreated(result.getCommit());
+
+ // Delete auto merge branch
+ deleteAutoMergeBranch(result.getCommit());
+ // Trigger AutoMerge computation
+ assertThat(gApi.changes().id(result.getChangeId()).revision(1).file("foo").blameRequest().get())
+ .isNotEmpty();
+ assertNoAutoMergeCreated(result.getCommit());
+ }
+
+ @Test
+ public void pushWorksIfAutoMergeExists() throws Exception {
+ PushOneCommit m =
+ pushFactory.create(
+ admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+ m.setParents(ImmutableList.of(parent1, parent2));
+ PushOneCommit.Result result = m.to("refs/for/master");
+ result.assertOkStatus();
+ assertAutoMergeCreated(result.getCommit());
+
+ // Delete change and push commit again.
+ gApi.changes().id(result.getChangeId()).delete();
+
+ // Push again successfully and check that AutoMerge commit is still there
+ result = m.to("refs/for/master");
+ result.assertOkStatus();
+ assertAutoMergeCreated(result.getCommit());
+ }
+
+ private void assertAutoMergeCreated(ObjectId mergeCommit) throws Exception {
+ try (Repository repo = repoManager.openRepository(project)) {
+ assertThat(repo.exactRef(RefNames.refsCacheAutomerge(mergeCommit.name()))).isNotNull();
+ }
+ }
+
+ private void assertNoAutoMergeCreated(ObjectId mergeCommit) throws Exception {
+ try (Repository repo = repoManager.openRepository(project)) {
+ assertThat(repo.exactRef(RefNames.refsCacheAutomerge(mergeCommit.name()))).isNull();
+ }
+ }
+
+ private void deleteAutoMergeBranch(ObjectId mergeCommit) throws Exception {
+ try (Repository repo = repoManager.openRepository(project)) {
+ RefUpdate ru = repo.updateRef(RefNames.refsCacheAutomerge(mergeCommit.name()));
+ ru.setForceUpdate(true);
+ assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
+ }
+ assertNoAutoMergeCreated(mergeCommit);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java b/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
index 1ca019e..7598062 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
@@ -32,12 +32,12 @@
public boolean runAs;
public boolean runGC;
public boolean streamEvents;
+ public boolean viewAccess;
public boolean viewAllAccounts;
public boolean viewCaches;
public boolean viewConnections;
public boolean viewPlugins;
public boolean viewQueue;
- public boolean viewAccess;
static class QueryLimit {
short min;
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/PluginProvidedChildRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/PluginProvidedChildRestApiBindingsIT.java
index 22feeb7..23a1d23 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/PluginProvidedChildRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/PluginProvidedChildRestApiBindingsIT.java
@@ -15,12 +15,16 @@
package com.google.gerrit.acceptance.rest.binding;
import static com.google.gerrit.server.change.RevisionResource.REVISION_KIND;
+import static com.google.gerrit.server.change.RobotCommentResource.ROBOT_COMMENT_KIND;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.rest.util.RestApiCallHelper;
import com.google.gerrit.acceptance.rest.util.RestCall;
+import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.ChildCollection;
@@ -34,6 +38,8 @@
import com.google.gerrit.extensions.restapi.RestResource;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.change.RevisionResource;
+import com.google.gerrit.server.change.RobotCommentResource;
+import com.google.gerrit.testing.TestCommentHelper;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -47,6 +53,7 @@
* not test the functionality of the plugin REST endpoints.
*/
public class PluginProvidedChildRestApiBindingsIT extends AbstractDaemonTest {
+ @Inject private TestCommentHelper testCommentHelper;
/** Resource to bind a child collection. */
public static final TypeLiteral<RestView<TestPluginResource>> TEST_KIND =
@@ -54,7 +61,7 @@
private static final String PLUGIN_NAME = "my-plugin";
- private static final ImmutableSet<RestCall> TEST_CALLS =
+ private static final ImmutableSet<RestCall> REVISION_TEST_CALLS =
ImmutableSet.of(
// Calls that have the plugin name as part of the collection name
RestCall.get("/changes/%s/revisions/%s/" + PLUGIN_NAME + "~test-collection/"),
@@ -70,6 +77,9 @@
RestCall.post("/changes/%s/revisions/%s/test-collection/"),
RestCall.post("/changes/%s/revisions/%s/test-collection/1/update"));
+ private static final ImmutableSet<RestCall> ROBOTCOMMENT_TEST_CALLS =
+ ImmutableSet.of(RestCall.delete("/changes/%s/revisions/%s/robotcomments/%s"));
+
/**
* Module for all sys bindings.
*
@@ -89,6 +99,7 @@
postOnCollection(TEST_KIND).to(TestPostOnCollection.class);
post(TEST_KIND, "update").to(TestPost.class);
get(TEST_KIND, "detail").to(TestGet.class);
+ delete(ROBOT_COMMENT_KIND).to(TestDelete.class);
}
});
}
@@ -148,15 +159,46 @@
}
}
+ @Singleton
+ static class TestDelete implements RestModifyView<RobotCommentResource, String> {
+ @Override
+ public Response<?> apply(RobotCommentResource resource, String input) throws Exception {
+ return Response.none();
+ }
+ }
+
@Test
- public void testEndpoints() throws Exception {
+ public void testRevisionEndpoints() throws Exception {
PatchSet.Id patchSetId = createChange().getPatchSetId();
try (AutoCloseable ignored = installPlugin(PLUGIN_NAME, MyPluginSysModule.class, null, null)) {
RestApiCallHelper.execute(
adminRestSession,
- TEST_CALLS.asList(),
+ REVISION_TEST_CALLS.asList(),
String.valueOf(patchSetId.changeId().get()),
String.valueOf(patchSetId.get()));
}
}
+
+ @Test
+ public void testRobotCommentEndpoints() throws Exception {
+ PatchSet.Id patchSetId = createChange().getPatchSetId();
+ String robotCommentUuid = createRobotComment(patchSetId.changeId());
+ try (AutoCloseable ignored = installPlugin(PLUGIN_NAME, MyPluginSysModule.class, null, null)) {
+ RestApiCallHelper.execute(
+ adminRestSession,
+ ROBOTCOMMENT_TEST_CALLS.asList(),
+ String.valueOf(patchSetId.changeId().get()),
+ String.valueOf(patchSetId.get()),
+ robotCommentUuid);
+ }
+ }
+
+ private String createRobotComment(Change.Id changeId) throws Exception {
+ testCommentHelper.addRobotComment(
+ changeId, TestCommentHelper.createRobotCommentInput(PushOneCommit.FILE_NAME));
+ return Iterables.getOnlyElement(
+ Iterables.getOnlyElement(
+ gApi.changes().id(changeId.get()).current().robotComments().values()))
+ .id;
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
index 7e6a822..61b7360 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
@@ -37,6 +37,7 @@
import com.google.gerrit.entities.AttentionSetUpdate;
import com.google.gerrit.entities.AttentionSetUpdate.Operation;
import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.api.changes.AttentionSetInput;
@@ -495,6 +496,44 @@
}
@Test
+ public void readyForReviewHasNoEffectOnReadyChanges() throws Exception {
+ PushOneCommit.Result r = createChange();
+ change(r)
+ .current()
+ .review(ReviewInput.create().reviewer(user.email()).blockAutomaticAttentionSetRules());
+
+ change(r).current().review(ReviewInput.create().setWorkInProgress(false));
+ assertThat(r.getChange().attentionSet()).isEmpty();
+
+ change(r).current().review(ReviewInput.create().setReady(true));
+ assertThat(r.getChange().attentionSet()).isEmpty();
+ }
+
+ @Test
+ public void workInProgressHasNoEffectOnWorkInProgressChanges() throws Exception {
+ PushOneCommit.Result r = createChange();
+ change(r)
+ .current()
+ .review(
+ ReviewInput.create()
+ .reviewer(user.email())
+ .setWorkInProgress(true)
+ .addUserToAttentionSet(user.email(), /* reason= */ "reason"));
+
+ change(r).current().review(ReviewInput.create().setWorkInProgress(true));
+ AttentionSetUpdate attentionSet = Iterables.getOnlyElement(r.getChange().attentionSet());
+ assertThat(attentionSet).hasAccountIdThat().isEqualTo(user.id());
+ assertThat(attentionSet).hasOperationThat().isEqualTo(AttentionSetUpdate.Operation.ADD);
+ assertThat(attentionSet).hasReasonThat().isEqualTo("reason");
+
+ change(r).current().review(ReviewInput.create().setReady(false));
+ attentionSet = Iterables.getOnlyElement(r.getChange().attentionSet());
+ assertThat(attentionSet).hasAccountIdThat().isEqualTo(user.id());
+ assertThat(attentionSet).hasOperationThat().isEqualTo(AttentionSetUpdate.Operation.ADD);
+ assertThat(attentionSet).hasReasonThat().isEqualTo("reason");
+ }
+
+ @Test
public void rebaseDoesNotAddToAttentionSet() throws Exception {
PushOneCommit.Result r = createChange();
change(r).setWorkInProgress();
@@ -1318,6 +1357,21 @@
}
@Test
+ public void robotReviewWithNegativeLabelDoesNotAddOwnerOnWorkInProgressChanges()
+ throws Exception {
+ TestAccount robot =
+ accountCreator.create(
+ "robot2", "robot2@example.com", "Ro Bot", "Ro", ServiceUserClassifier.SERVICE_USERS);
+ PushOneCommit.Result r = createChange();
+ gApi.changes().id(r.getChangeId()).setWorkInProgress();
+
+ requestScopeOperations.setApiUser(robot.id());
+ change(r).current().review(ReviewInput.dislike());
+
+ assertThat(r.getChange().attentionSet()).isEmpty();
+ }
+
+ @Test
public void robotReviewWithNegativeLabelAddsOwner() throws Exception {
TestAccount robot =
accountCreator.create(
@@ -1720,6 +1774,40 @@
.isEqualTo(Operation.REMOVE);
}
+ @Test
+ public void deleteSelfVotesDoesNotAddToAttentionSet() throws Exception {
+ PushOneCommit.Result r = createChange();
+ approve(r.getChangeId());
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .reviewer(admin.id().toString())
+ .deleteVote(LabelId.CODE_REVIEW);
+
+ assertThat(getAttentionSetUpdates(r.getChange().getId())).isEmpty();
+ }
+
+ @Test
+ public void deleteVotesOfOthersAddThemToAttentionSet() throws Exception {
+ PushOneCommit.Result r = createChange();
+
+ requestScopeOperations.setApiUser(user.id());
+ recommend(r.getChangeId());
+
+ requestScopeOperations.setApiUser(admin.id());
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .reviewer(user.id().toString())
+ .deleteVote(LabelId.CODE_REVIEW);
+
+ AttentionSetUpdate attentionSet =
+ Iterables.getOnlyElement(getAttentionSetUpdatesForUser(r, user));
+ assertThat(attentionSet).hasAccountIdThat().isEqualTo(user.id());
+ assertThat(attentionSet).hasOperationThat().isEqualTo(AttentionSetUpdate.Operation.ADD);
+ assertThat(attentionSet).hasReasonThat().isEqualTo("Their vote was deleted");
+ }
+
private List<AttentionSetUpdate> getAttentionSetUpdatesForUser(
PushOneCommit.Result r, TestAccount account) {
return getAttentionSetUpdates(r.getChange().getId()).stream()
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/ChangeMetaIT.java b/javatests/com/google/gerrit/acceptance/rest/change/ChangeMetaIT.java
index e025c52..2cd04ed 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/ChangeMetaIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/ChangeMetaIT.java
@@ -104,7 +104,7 @@
protected static class PluginDefinedSimpleAttributeModule extends AbstractModule {
static class MyMetaHash extends PluginDefinedInfo {
String myMetaRef;
- };
+ }
static PluginDefinedInfo newMyMetaHash(ChangeData cd) {
MyMetaHash mmh = new MyMetaHash();
@@ -125,6 +125,7 @@
}
@Test
+ @SuppressWarnings("unchecked")
public void pluginDefinedAttribute() throws Exception {
try (AutoCloseable ignored =
installPlugin("my-plugin", PluginDefinedSimpleAttributeModule.class)) {
@@ -133,7 +134,6 @@
gApi.changes().id(changeId).setMessage("before\n\n" + "Change-Id: " + result.getChangeId());
ChangeInfo before = gApi.changes().id(changeId).get();
gApi.changes().id(changeId).setMessage("after\n\n" + "Change-Id: " + result.getChangeId());
- ChangeInfo after = gApi.changes().id(changeId).get();
RestResponse resp =
adminRestSession.get("/changes/" + changeId + "/?meta=" + before.metaRevId);
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/GetMetaDiffIT.java b/javatests/com/google/gerrit/acceptance/rest/change/GetMetaDiffIT.java
new file mode 100644
index 0000000..2cb96e8
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/rest/change/GetMetaDiffIT.java
@@ -0,0 +1,200 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.rest.change;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
+import com.google.gerrit.extensions.api.changes.HashtagsInput;
+import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInfoDifference;
+import org.junit.Test;
+
+public class GetMetaDiffIT extends AbstractDaemonTest {
+
+ private static final String UNSAVED_REV_ID = "0000000000000000000000000000000000000001";
+ private static final String TOPIC = "topic";
+ private static final String HASHTAG = "hashtag";
+
+ @Test
+ public void metaDiff() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeApi chApi = gApi.changes().id(ch.getChangeId());
+ chApi.topic(TOPIC);
+ ChangeInfo oldInfo = chApi.get();
+ chApi.topic(TOPIC + "-2");
+ chApi.setHashtags(new HashtagsInput(ImmutableSet.of(HASHTAG)));
+ ChangeInfo newInfo = chApi.get();
+
+ ChangeInfoDifference difference = chApi.metaDiff(oldInfo.metaRevId, newInfo.metaRevId);
+
+ assertThat(difference.added().topic).isEqualTo(newInfo.topic);
+ assertThat(difference.added().hashtags).isNotNull();
+ assertThat(difference.added().hashtags).containsExactly(HASHTAG);
+ assertThat(difference.removed().topic).isEqualTo(oldInfo.topic);
+ assertThat(difference.removed().hashtags).isNull();
+ }
+
+ @Test
+ public void metaDiffReturnsSuccessful() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeInfo info = gApi.changes().id(ch.getChangeId()).get();
+
+ RestResponse resp =
+ adminRestSession.get("/changes/" + ch.getChangeId() + "/meta_diff/?meta=" + info.metaRevId);
+
+ resp.assertOK();
+ }
+
+ @Test
+ public void metaDiffUnreachableNewSha1() throws Exception {
+ PushOneCommit.Result ch1 = createChange();
+ PushOneCommit.Result ch2 = createChange();
+
+ ChangeInfo info2 = gApi.changes().id(ch2.getChangeId()).get();
+
+ RestResponse resp =
+ adminRestSession.get(
+ "/changes/" + ch1.getChangeId() + "/meta_diff/?meta=" + info2.metaRevId);
+
+ resp.assertStatus(412);
+ }
+
+ @Test
+ public void metaDiffInvalidNewSha1() throws Exception {
+ PushOneCommit.Result ch = createChange();
+
+ RestResponse resp =
+ adminRestSession.get("/changes/" + ch.getChangeId() + "/meta_diff/?meta=invalid");
+
+ resp.assertBadRequest();
+ }
+
+ @Test
+ public void metaDiffInvalidOldSha1() throws Exception {
+ PushOneCommit.Result ch = createChange();
+
+ RestResponse resp =
+ adminRestSession.get("/changes/" + ch.getChangeId() + "/meta_diff/?old=invalid");
+
+ resp.assertBadRequest();
+ }
+
+ @Test
+ public void metaDiffWithNewSha1NotInRepo() throws Exception {
+ PushOneCommit.Result ch = createChange();
+
+ RestResponse resp =
+ adminRestSession.get("/changes/" + ch.getChangeId() + "/meta_diff/?meta=" + UNSAVED_REV_ID);
+
+ resp.assertStatus(412);
+ }
+
+ @Test
+ public void metaDiffUnreachableOldSha1UsesDefault() throws Exception {
+ PushOneCommit.Result ch1 = createChange();
+ PushOneCommit.Result ch2 = createChange();
+ gApi.changes().id(ch1.getChangeId()).topic("intermediate-topic");
+ gApi.changes().id(ch1.getChangeId()).topic(TOPIC);
+ ChangeInfo info1 = gApi.changes().id(ch1.getChangeId()).get();
+ ChangeInfo info2 = gApi.changes().id(ch2.getChangeId()).get();
+
+ ChangeInfoDifference difference =
+ gApi.changes().id(ch1.getChangeId()).metaDiff(info2.metaRevId, info1.metaRevId);
+
+ assertThat(difference.added().topic).isEqualTo(TOPIC);
+ assertThat(difference.removed().topic).isNull();
+ }
+
+ @Test
+ public void metaDiffWithOldSha1NotInRepoUsesDefault() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ gApi.changes().id(ch.getChangeId()).topic("intermediate-topic");
+ gApi.changes().id(ch.getChangeId()).topic(TOPIC);
+ ChangeInfo info = gApi.changes().id(ch.getChangeId()).get();
+
+ ChangeInfoDifference difference =
+ gApi.changes().id(ch.getChangeId()).metaDiff(UNSAVED_REV_ID, info.metaRevId);
+
+ assertThat(difference.added().topic).isEqualTo(TOPIC);
+ assertThat(difference.removed().topic).isNull();
+ }
+
+ @Test
+ public void metaDiffNoOldMetaGivenUsesPatchSetBeforeNew() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeApi chApi = gApi.changes().id(ch.getChangeId());
+ chApi.topic(TOPIC);
+ ChangeInfo newInfo = chApi.get();
+ chApi.topic(TOPIC + "2");
+
+ ChangeInfoDifference difference = chApi.metaDiff(null, newInfo.metaRevId);
+
+ assertThat(difference.added().topic).isEqualTo(TOPIC);
+ assertThat(difference.removed().topic).isNull();
+ }
+
+ @Test
+ public void metaDiffNoNewMetaGivenUsesCurrentPatchSet() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeApi chApi = gApi.changes().id(ch.getChangeId());
+ ChangeInfo oldInfo = chApi.get();
+ chApi.topic(TOPIC);
+
+ ChangeInfoDifference difference = chApi.metaDiff(oldInfo.metaRevId, null);
+
+ assertThat(difference.added().topic).isEqualTo(TOPIC);
+ assertThat(difference.removed().topic).isNull();
+ }
+
+ @Test
+ public void metaDiffWithoutOptionDoesNotIncludeExtraInformation() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeApi chApi = gApi.changes().id(ch.getChangeId());
+ ChangeInfo oldInfo = chApi.get();
+ amendChange(ch.getChangeId());
+ ChangeInfo newInfo = chApi.get();
+
+ ChangeInfoDifference difference = chApi.metaDiff(oldInfo.metaRevId, newInfo.metaRevId);
+
+ assertThat(difference.added().currentRevision).isNull();
+ assertThat(difference.removed().currentRevision).isNull();
+ }
+
+ @Test
+ public void metaDiffWithOptionIncludesExtraInformation() throws Exception {
+ PushOneCommit.Result ch = createChange();
+ ChangeApi chApi = gApi.changes().id(ch.getChangeId());
+ ChangeInfo oldInfo = chApi.get(ListChangesOption.CURRENT_REVISION);
+ amendChange(ch.getChangeId());
+ ChangeInfo newInfo = chApi.get(ListChangesOption.CURRENT_REVISION);
+
+ ChangeInfoDifference difference =
+ chApi.metaDiff(
+ oldInfo.metaRevId,
+ newInfo.metaRevId,
+ ImmutableSet.of(ListChangesOption.CURRENT_REVISION));
+
+ assertThat(newInfo.currentRevision).isNotNull();
+ assertThat(oldInfo.currentRevision).isNotNull();
+ assertThat(difference.added().currentRevision).isEqualTo(newInfo.currentRevision);
+ assertThat(difference.removed().currentRevision).isEqualTo(oldInfo.currentRevision);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index e5c5952..7090074 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -26,6 +26,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.net.HttpHeaders;
@@ -40,6 +41,7 @@
import com.google.gerrit.entities.BooleanProjectConfig;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.api.projects.ConfigInfo;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.api.projects.ProjectInput;
@@ -47,6 +49,7 @@
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
@@ -304,13 +307,15 @@
}
@Test
- public void createProjectWithEmptyCommit() throws Exception {
+ @GerritConfig(name = "gerrit.defaultBranch", value = "main")
+ public void createPermissionOnlyProject_WhenDefaultBranchIsSet() throws Exception {
String newProjectName = name("newProject");
ProjectInput in = new ProjectInput();
in.name = newProjectName;
- in.createEmptyCommit = true;
+ in.permissionsOnly = true;
gApi.projects().create(in);
- assertEmptyCommit(newProjectName, "refs/heads/master");
+ // For permissionOnly, don't use host-level default branch.
+ assertHead(newProjectName, RefNames.REFS_CONFIG);
}
@Test
@@ -344,6 +349,72 @@
}
@Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "main")
+ public void createProject_WhenDefaultBranchIsSet() throws Exception {
+ String newProjectName = name("newProject");
+ gApi.projects().create(newProjectName).get();
+ ImmutableMap<String, BranchInfo> branches = getProjectBranches(newProjectName);
+ // HEAD symbolic ref is set to the default, but the actual ref is not created.
+ assertThat(branches.keySet()).containsExactly("HEAD", "refs/meta/config");
+ assertHead(newProjectName, "refs/heads/main");
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "main")
+ public void createProjectWithEmptyCommit_WhenDefaultBranchIsSet() throws Exception {
+ String newProjectName = name("newProject");
+ ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
+ in.createEmptyCommit = true;
+ gApi.projects().create(in);
+ ImmutableMap<String, BranchInfo> branches = getProjectBranches(newProjectName);
+ // HEAD symbolic ref is set to the default, and the actual ref is created.
+ assertThat(branches.keySet()).containsExactly("HEAD", "refs/meta/config", "refs/heads/main");
+ assertHead(newProjectName, "refs/heads/main");
+ assertEmptyCommit(newProjectName, "HEAD", "refs/heads/main");
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "refs/heads/main")
+ public void createProject_WhenDefaultBranchIsSet_WithBranches() throws Exception {
+ // Host-level default only applies if no branches were passed in the input
+ String newProjectName = name("newProject");
+ ProjectInput in = new ProjectInput();
+ in.name = newProjectName;
+ in.createEmptyCommit = true;
+ in.branches = ImmutableList.of("refs/heads/test", "release");
+ gApi.projects().create(in);
+ ImmutableMap<String, BranchInfo> branches = getProjectBranches(newProjectName);
+ assertThat(branches.keySet())
+ .containsExactly("HEAD", "refs/meta/config", "refs/heads/test", "refs/heads/release");
+ assertHead(newProjectName, "refs/heads/test");
+ assertEmptyCommit(newProjectName, "refs/heads/test", "refs/heads/release");
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "refs/users/self")
+ public void createProject_WhenDefaultBranchIsSet_ToGerritRef() throws Exception {
+ String newProjectName = name("newProject");
+ Throwable thrown =
+ assertThrows(ResourceConflictException.class, () -> gApi.projects().create(newProjectName));
+ assertThat(thrown).hasCauseThat().isInstanceOf(ValidationException.class);
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains("Cannot create a project with branch refs/users/self");
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "refs~main")
+ public void createProject_WhenDefaultBranchIsSet_ToInvalidBranch() throws Exception {
+ String newProjectName = name("newProject");
+ Throwable thrown =
+ assertThrows(BadRequestException.class, () -> gApi.projects().create(newProjectName));
+ assertThat(thrown)
+ .hasMessageThat()
+ .isEqualTo("Branch \"refs/heads/refs~main\" is not a valid name.");
+ }
+
+ @Test
public void createProjectWithCapability() throws Exception {
projectOperations
.allProjectsForUpdate()
@@ -494,12 +565,6 @@
assertThat(cfg.defaultSubmitType.inheritedValue).isEqualTo(SubmitType.MERGE_ALWAYS);
}
- private void assertHead(String projectName, String expectedRef) throws Exception {
- try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
- assertThat(repo.exactRef(Constants.HEAD).getTarget().getName()).isEqualTo(expectedRef);
- }
- }
-
private void assertEmptyCommit(String projectName, String... refs) throws Exception {
Project.NameKey projectKey = Project.nameKey(projectName);
try (Repository repo = repoManager.openRepository(projectKey);
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
index ffdbd8e..83d2256 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -175,7 +175,7 @@
expectedCfg.setString("s3", null, "k5", "childValue3");
expectedCfg.setString("s3", "ss", "k6", "childValue4");
- assertThat(state.getConfig(configName).getWithInheritance(true).toText())
+ assertThat(state.getConfig(configName).getWithInheritance(/* merge= */ true).toText())
.isEqualTo(expectedCfg.toText());
assertThat(state.getConfig(configName).get().toText()).isEqualTo(cfg.toText());
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
index 20b9882..9bd8e9c 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
@@ -26,6 +26,7 @@
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
import com.google.gerrit.extensions.client.Comment;
import com.google.gerrit.extensions.client.Side;
@@ -35,8 +36,10 @@
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import org.eclipse.jgit.lib.ObjectId;
import org.junit.Before;
import org.junit.Test;
@@ -54,15 +57,37 @@
private static final String FILE_CONTENT =
String.join("\n", "Line 1 of file", "", "Line 3 of file", "", "", "Line 6 of file");
+ private static final ObjectId dummyCommit =
+ ObjectId.fromString("93e2901bc0b4719ef6081ee6353b49c9cdd97614");
@Inject private RequestScopeOperations requestScopeOperations;
@Before
- public void setUp() {
+ public void setup() throws Exception {
requestScopeOperations.setApiUser(user.id());
}
@Test
+ public void commentContextForGitSubmoduleFiles() throws Exception {
+ String submodulePath = "submodule_path";
+
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo).addGitSubmodule(submodulePath, dummyCommit);
+ PushOneCommit.Result pushResult = push.to("refs/for/master");
+ String changeId = pushResult.getChangeId();
+ CommentInput comment =
+ CommentsUtil.newComment(submodulePath, Side.REVISION, 1, "comment", false);
+ CommentsUtil.addComments(gApi, changeId, pushResult.getCommit().name(), comment);
+
+ List<CommentInfo> comments =
+ gApi.changes().id(changeId).commentsRequest().withContext(true).getAsList();
+ assertThat(comments).hasSize(1);
+ assertThat(comments.get(0).path).isEqualTo(submodulePath);
+ assertThat(comments.get(0).contextLines)
+ .isEqualTo(createContextLines("1", "Subproject commit " + dummyCommit.getName()));
+ }
+
+ @Test
public void commentContextForCommitMessageForLineComment() throws Exception {
PushOneCommit.Result result =
createChange(testRepo, "master", SUBJECT, FILE_NAME, FILE_CONTENT, "topic");
@@ -198,6 +223,42 @@
}
@Test
+ public void listChangeDraftsWithContextEnabled() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ PushOneCommit.Result r2 =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ PushOneCommit.SUBJECT,
+ FILE_NAME,
+ "line_1\nline_2\nline_3",
+ r1.getChangeId())
+ .to("refs/for/master");
+
+ DraftInput in = CommentsUtil.newDraft(FILE_NAME, Side.REVISION, 2, "comment 1");
+ gApi.changes().id(r2.getChangeId()).revision(r2.getCommit().name()).createDraft(in);
+
+ // Test the getAsList interface
+ List<CommentInfo> comments =
+ gApi.changes().id(r2.getChangeId()).draftsRequest().withContext(true).getAsList();
+ assertThat(comments).hasSize(1);
+ assertThat(comments.get(0).message).isEqualTo("comment 1");
+ assertThat(comments.get(0).contextLines)
+ .containsExactlyElementsIn(createContextLines("2", "line_2"));
+
+ // Also test the get interface
+ Map<String, List<CommentInfo>> commentsMap =
+ gApi.changes().id(r2.getChangeId()).draftsRequest().withContext(true).get();
+ assertThat(commentsMap).hasSize(1);
+ assertThat(commentsMap.values().iterator().next()).hasSize(1);
+ CommentInfo onlyComment = commentsMap.values().iterator().next().get(0);
+ assertThat(onlyComment.message).isEqualTo("comment 1");
+ assertThat(onlyComment.contextLines)
+ .containsExactlyElementsIn(createContextLines("2", "line_2"));
+ }
+
+ @Test
public void commentContextForCommentsOnDifferentPatchsets() throws Exception {
PushOneCommit.Result r1 = createChange();
diff --git a/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java b/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
index 801288a..2692584 100644
--- a/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
@@ -34,7 +34,7 @@
import com.google.gerrit.server.quota.QuotaResponse;
import com.google.inject.Module;
import java.util.Collections;
-import org.eclipse.jgit.api.errors.TooLargeObjectInPackException;
+import org.eclipse.jgit.api.errors.TooLargePackException;
import org.eclipse.jgit.api.errors.TransportException;
import org.junit.Before;
import org.junit.Test;
@@ -77,7 +77,7 @@
@Test
public void pushWithAvailableTokens() throws Exception {
when(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
- .thenReturn(singletonAggregation(ok(276L)));
+ .thenReturn(singletonAggregation(ok(277L)));
when(quotaBackendWithResource.requestTokens(eq(REPOSITORY_SIZE_GROUP), anyLong()))
.thenReturn(singletonAggregation(ok()));
when(quotaBackendWithUser.project(project)).thenReturn(quotaBackendWithResource);
@@ -91,12 +91,10 @@
when(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
.thenReturn(singletonAggregation(ok(availableTokens)));
when(quotaBackendWithUser.project(project)).thenReturn(quotaBackendWithResource);
- TooLargeObjectInPackException thrown =
- assertThrows(TooLargeObjectInPackException.class, () -> pushCommit());
- assertThat(thrown).hasMessageThat().contains("Object too large");
- assertThat(thrown)
- .hasMessageThat()
- .contains(String.format("Max object size limit is %d bytes.", availableTokens));
+ assertThat(assertThrows(TooLargePackException.class, () -> pushCommit()).getMessage())
+ .contains(
+ String.format(
+ "Pack exceeds the limit of %d bytes, rejecting the pack", availableTokens));
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java b/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
index 5cbc767..0585f74 100644
--- a/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/rules/RulesIT.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
@@ -27,7 +28,9 @@
import com.google.gerrit.server.project.SubmitRuleOptions;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Map;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Repository;
import org.junit.Test;
@@ -39,7 +42,7 @@
@NoHttpd
public class RulesIT extends AbstractDaemonTest {
private static final String RULE_TEMPLATE =
- "submit_rule(submit(W)) :- \n" + "%s,\n" + "W = label('OK', ok(user(1000000))).";
+ "submit_rule(submit(W)) :- \n%s,\nW = label('OK', ok(user(1000000))).";
@Inject private ProjectOperations projectOperations;
@Inject private SubmitRuleEvaluator.Factory evaluatorFactory;
@@ -89,12 +92,116 @@
assertThat(statusForRuleRemoveFile()).isEqualTo(SubmitRecord.Status.OK);
}
+ @Test
+ public void testCommitDelta_pass() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('file1\\.txt')");
+ assertThat(statusForRuleAddFile("file1.txt")).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_fail() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('no such file')");
+ assertThat(statusForRuleAddFile("file1.txt")).isEqualTo(SubmitRecord.Status.RULE_ERROR);
+ }
+
+ @Test
+ public void testCommitDelta_addOwners_pass() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('OWNERS', add, _, _)");
+ assertThat(statusForRuleAddFile("foo/OWNERS")).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_addOwners_fail() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('OWNERS', add, _, _)");
+ assertThat(statusForRuleAddFile("foobar")).isEqualTo(SubmitRecord.Status.RULE_ERROR);
+ }
+
+ @Test
+ public void testCommitDelta_regexp() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*')");
+ assertThat(statusForRuleAddFile("foo/bar")).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_add_provideNewName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*', _, 'foo')");
+ assertThat(statusForRuleAddFile("foo")).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_modify_provideNewName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*', _, 'a.txt')");
+ assertThat(statusForRuleModifyFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_delete_provideNewName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*', _, 'a.txt')");
+ assertThat(statusForRuleRemoveFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_rename_provideOldName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*', _, 'a.txt')");
+ assertThat(statusForRuleRenamedFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_rename_provideNewName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('.*', _, 'b.txt')");
+ assertThat(statusForRuleRenamedFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_rename_matchOldName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('a\\.txt')");
+ assertThat(statusForRuleRenamedFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
+ @Test
+ public void testCommitDelta_rename_matchNewName() throws Exception {
+ modifySubmitRules("gerrit:commit_delta('b\\.txt')");
+ assertThat(statusForRuleRenamedFile()).isEqualTo(SubmitRecord.Status.OK);
+ }
+
private SubmitRecord.Status statusForRule() throws Exception {
String oldHead = projectOperations.project(project).getHead("master").name();
- PushOneCommit.Result result1 =
+ PushOneCommit.Result result =
pushFactory.create(user.newIdent(), testRepo).to("refs/for/master");
testRepo.reset(oldHead);
- return getStatus(result1);
+ return getStatus(result);
+ }
+
+ private SubmitRecord.Status statusForRuleAddFile(String... filenames) throws Exception {
+ Map<String, String> fileToContentMap =
+ Arrays.stream(filenames).collect(ImmutableMap.toImmutableMap(f -> f, f -> "file content"));
+ String oldHead = projectOperations.project(project).getHead("master").name();
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "subject", fileToContentMap);
+ PushOneCommit.Result result = push.to("refs/for/master");
+ result.assertOkStatus();
+ testRepo.reset(oldHead);
+ return getStatus(result);
+ }
+
+ private SubmitRecord.Status statusForRuleModifyFile() throws Exception {
+ String oldHead = projectOperations.project(project).getHead("master").name();
+
+ // create a.txt
+ commitBuilder().add(PushOneCommit.FILE_NAME, "Hey, it's me!").message("subject").create();
+ pushHead(testRepo, "refs/heads/master", false);
+
+ PushOneCommit.Result result =
+ pushFactory
+ .create(
+ user.newIdent(),
+ testRepo,
+ "subject",
+ ImmutableMap.of(PushOneCommit.FILE_NAME, "I've changed!"))
+ .rmFile(PushOneCommit.FILE_NAME)
+ .to("refs/for/master");
+ testRepo.reset(oldHead);
+ return getStatus(result);
}
private SubmitRecord.Status statusForRuleRemoveFile() throws Exception {
@@ -110,15 +217,30 @@
return getStatus(result);
}
- private SubmitRecord.Status getStatus(PushOneCommit.Result result1) throws Exception {
- ChangeData cd = result1.getChange();
+ private SubmitRecord.Status statusForRuleRenamedFile() throws Exception {
+ String oldHead = projectOperations.project(project).getHead("master").name();
+
+ // create a.txt
+ commitBuilder().add(PushOneCommit.FILE_NAME, "Hey, it's me!").message("subject").create();
+ pushHead(testRepo, "refs/heads/master", false);
+
+ PushOneCommit.Result result =
+ pushFactory
+ .create(user.newIdent(), testRepo, "subject", ImmutableMap.of("b.txt", "Hey, it's me!"))
+ .rmFile(PushOneCommit.FILE_NAME)
+ .to("refs/for/master");
+ testRepo.reset(oldHead);
+ return getStatus(result);
+ }
+
+ private SubmitRecord.Status getStatus(PushOneCommit.Result result) throws Exception {
+ ChangeData cd = result.getChange();
Collection<SubmitRecord> records;
- try (AutoCloseable changeIndex = disableChangeIndex()) {
- try (AutoCloseable accountIndex = disableAccountIndex()) {
- SubmitRuleEvaluator ruleEvaluator = evaluatorFactory.create(SubmitRuleOptions.defaults());
- records = ruleEvaluator.evaluate(cd);
- }
+ try (AutoCloseable ignored1 = disableChangeIndex();
+ AutoCloseable ignored2 = disableAccountIndex()) {
+ SubmitRuleEvaluator ruleEvaluator = evaluatorFactory.create(SubmitRuleOptions.defaults());
+ records = ruleEvaluator.evaluate(cd);
}
assertThat(records).hasSize(1);
diff --git a/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
index 01b8eae..5429131 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/CreateProjectIT.java
@@ -19,6 +19,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.project.ProjectState;
import java.util.Optional;
@@ -85,4 +86,35 @@
assertThat(projectState).isPresent();
assertThat(projectState.get().getName()).isEqualTo(newProjectName);
}
+
+ @Test
+ public void withEmptyBranches() throws Exception {
+ String newProjectName = name("newProject");
+ adminSshSession.exec("gerrit create-project " + newProjectName);
+ adminSshSession.assertSuccess();
+ Optional<ProjectState> projectState = projectCache.get(Project.nameKey(newProjectName));
+ assertThat(projectState).isPresent();
+ assertHead(newProjectName, "refs/heads/master");
+ }
+
+ @Test
+ public void withInitBranches() throws Exception {
+ String newProjectName = name("newProject");
+ adminSshSession.exec("gerrit create-project --branch init-branch " + newProjectName);
+ adminSshSession.assertSuccess();
+ Optional<ProjectState> projectState = projectCache.get(Project.nameKey(newProjectName));
+ assertThat(projectState).isPresent();
+ assertHead(newProjectName, "refs/heads/init-branch");
+ }
+
+ @Test
+ @GerritConfig(name = "gerrit.defaultBranch", value = "refs/heads/main")
+ public void withEmptyBranches_WhenDefaultBranchIsSet() throws Exception {
+ String newProjectName = name("newProject");
+ adminSshSession.exec("gerrit create-project " + newProjectName);
+ adminSshSession.assertSuccess();
+ Optional<ProjectState> projectState = projectCache.get(Project.nameKey(newProjectName));
+ assertThat(projectState).isPresent();
+ assertHead(newProjectName, "refs/heads/main");
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImplTest.java b/javatests/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImplTest.java
index 00d01d6..7543ba8 100644
--- a/javatests/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImplTest.java
+++ b/javatests/com/google/gerrit/acceptance/testsuite/project/ProjectOperationsImplTest.java
@@ -595,6 +595,15 @@
}
@Test
+ public void removeAllAccessSections() {
+ projectOperations.allProjectsForUpdate().removeAllAccessSections().update();
+
+ assertThat(projectOperations.project(allProjects).getConfig())
+ .sectionValues("access")
+ .isEmpty();
+ }
+
+ @Test
public void updatingCapabilitiesNotAllowedForNonAllProjects() throws Exception {
Project.NameKey key = projectOperations.newProject().create();
assertThrows(
diff --git a/javatests/com/google/gerrit/entities/SubmitRecordTest.java b/javatests/com/google/gerrit/entities/SubmitRecordTest.java
index 0e832f4..e2a5787 100644
--- a/javatests/com/google/gerrit/entities/SubmitRecordTest.java
+++ b/javatests/com/google/gerrit/entities/SubmitRecordTest.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
@@ -67,4 +68,19 @@
assertThat(SubmitRecord.allRecordsOK(submitRecords)).isFalse();
}
+
+ @Test
+ public void deepCopy() {
+ SubmitRecord record = new SubmitRecord();
+ record.status = SubmitRecord.Status.CLOSED;
+ record.errorMessage = "ouch";
+ record.requirements =
+ ImmutableList.of(SubmitRequirement.builder().setFallbackText("foo").setType("baz").build());
+ SubmitRecord.Label label = new SubmitRecord.Label();
+ label.label = "Code-Review";
+ record.labels = ImmutableList.of(label);
+
+ assertThat(record).isNotSameInstanceAs(record.deepCopy());
+ assertThat(record).isEqualTo(record.deepCopy());
+ }
}
diff --git a/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java b/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
index a41d63b..09b0438 100644
--- a/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
+++ b/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
@@ -37,6 +37,7 @@
ChangeInfoDifference diff = ChangeInfoDiffer.getDifference(new ChangeInfo(), new ChangeInfo());
// Spot check a few fields, including collections and maps.
+ assertThat(diff.added()._number).isNull();
assertThat(diff.added().branch).isNull();
assertThat(diff.added().project).isNull();
assertThat(diff.added().currentRevision).isNull();
@@ -44,6 +45,7 @@
assertThat(diff.added().messages).isNull();
assertThat(diff.added().reviewers).isNull();
assertThat(diff.added().hashtags).isNull();
+ assertThat(diff.removed()._number).isNull();
assertThat(diff.removed().branch).isNull();
assertThat(diff.removed().project).isNull();
assertThat(diff.removed().currentRevision).isNull();
diff --git a/javatests/com/google/gerrit/server/cache/serialize/entities/BUILD b/javatests/com/google/gerrit/server/cache/serialize/entities/BUILD
index a8158fc..8df9292 100644
--- a/javatests/com/google/gerrit/server/cache/serialize/entities/BUILD
+++ b/javatests/com/google/gerrit/server/cache/serialize/entities/BUILD
@@ -8,6 +8,7 @@
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/cache/serialize/entities",
+ "//java/com/google/gerrit/server/util/time",
"//lib:guava",
"//lib:jgit",
"//lib:protobuf",
diff --git a/javatests/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializerTest.java b/javatests/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializerTest.java
new file mode 100644
index 0000000..8d301e4
--- /dev/null
+++ b/javatests/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializerTest.java
@@ -0,0 +1,61 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache.serialize.entities;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer.deserialize;
+import static com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer.serialize;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
+import com.google.gerrit.server.util.time.TimeUtil;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+
+public class InternalGroupSerializerTest {
+ static final InternalGroup MINIMAL_VALUES_SET =
+ InternalGroup.builder()
+ .setId(AccountGroup.id(123456))
+ .setNameKey(AccountGroup.nameKey("group name"))
+ .setOwnerGroupUUID(AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))
+ .setVisibleToAll(false)
+ .setGroupUUID(AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeef12345678"))
+ .setCreatedOn(TimeUtil.nowTs())
+ .setMembers(ImmutableSet.of(Account.id(123), Account.id(321)))
+ .setSubgroups(
+ ImmutableSet.of(
+ AccountGroup.uuid("87654321deadbeefdeadbeefdeadbeefdeadbeef"),
+ AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeef87654321")))
+ .build();
+
+ static final InternalGroup ALL_VALUES_SET =
+ MINIMAL_VALUES_SET
+ .toBuilder()
+ .setDescription("description")
+ .setRefState(ObjectId.fromString("12345678deadbeefdeadbeefdeadbeefdeadbeef"))
+ .build();
+
+ @Test
+ public void roundTrip() {
+ assertThat(deserialize(serialize(ALL_VALUES_SET))).isEqualTo(ALL_VALUES_SET);
+ }
+
+ @Test
+ public void roundTripWithMinimalValues() {
+ assertThat(deserialize(serialize(MINIMAL_VALUES_SET))).isEqualTo(MINIMAL_VALUES_SET);
+ }
+}
diff --git a/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
new file mode 100644
index 0000000..7832bec
--- /dev/null
+++ b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
@@ -0,0 +1,54 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.gerrit.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.entities.Project.NameKey;
+import java.util.SortedSet;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitRepositoryManagerTest {
+
+ private GitRepositoryManager objectUnderTest;
+
+ @Before
+ public void setUp() throws Exception {
+ objectUnderTest = new TestGitRepositoryManager();
+ }
+
+ @Test
+ public void shouldReturnFalseWhenDefaultCanPerformGC() {
+ assertThat(objectUnderTest.canPerformGC()).isFalse();
+ }
+
+ private static class TestGitRepositoryManager implements GitRepositoryManager {
+ @Override
+ public Repository openRepository(NameKey name) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public Repository createRepository(NameKey name) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public SortedSet<NameKey> list() {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index 8ab7dd2..febb142 100644
--- a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -252,6 +252,11 @@
() -> newRepoManager.createRepository(Project.nameKey("A")));
}
+ @Test
+ public void testRepositoryCanPerformGC() throws Exception {
+ assertThat(repoManager.canPerformGC()).isTrue();
+ }
+
private void createSymLink(Project.NameKey project, String link) throws IOException {
Path base = repoManager.getBasePath(project);
Path projectDir = base.resolve(project.get() + ".git");
diff --git a/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java b/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
index 20fe387..e24d481 100644
--- a/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
+++ b/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
@@ -20,13 +20,13 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import java.io.IOException;
diff --git a/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java b/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
index bf2ade9..7da4785 100644
--- a/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
+++ b/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
@@ -22,8 +22,8 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.AccountGroupByIdAudit;
import com.google.gerrit.entities.AccountGroupMemberAudit;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.account.GroupUuid;
-import com.google.gerrit.server.group.InternalGroup;
import java.sql.Timestamp;
import java.util.Set;
import org.eclipse.jgit.lib.PersonIdent;
diff --git a/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java b/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
index c1f3615..1c41c4c 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupConfigTest.java
@@ -28,11 +28,11 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupDescription;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.testing.InternalGroupSubject;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gerrit.truth.OptionalSubject;
diff --git a/javatests/com/google/gerrit/server/patch/DiffOperationsTest.java b/javatests/com/google/gerrit/server/patch/DiffOperationsTest.java
new file mode 100644
index 0000000..5bf5154
--- /dev/null
+++ b/javatests/com/google/gerrit/server/patch/DiffOperationsTest.java
@@ -0,0 +1,137 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.patch;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
+import com.google.gerrit.server.util.time.TimeUtil;
+import com.google.gerrit.testing.InMemoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import java.io.IOException;
+import java.util.Map;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TreeFormatter;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Test class for diff related logic of {@link DiffOperations}. */
+public class DiffOperationsTest {
+ @Inject private GitRepositoryManager repoManager;
+ @Inject private DiffOperations diffOperations;
+
+ private static final Project.NameKey testProjectName = Project.nameKey("test-project");
+ private Repository repo;
+
+ private final String fileName1 = "file_1.txt";
+ private final String fileContent1 = "File content 1";
+ private final String fileName2 = "file_2.txt";
+ private final String fileContent2 = "File content 2";
+
+ @Before
+ public void setUpInjector() throws Exception {
+ Injector injector = Guice.createInjector(new InMemoryModule());
+ injector.injectMembers(this);
+ repo = repoManager.createRepository(testProjectName);
+ }
+
+ @Test
+ public void diffModifiedFileAgainstParent() throws Exception {
+ ImmutableMap<String, String> oldFiles =
+ ImmutableMap.of(fileName1, fileContent1, fileName2, fileContent2);
+ ObjectId oldCommitId = createCommit(repo, null, oldFiles);
+
+ ImmutableMap<String, String> newFiles =
+ ImmutableMap.of(fileName1, fileContent1, fileName2, fileContent2 + "\nnew line here");
+ ObjectId newCommitId = createCommit(repo, oldCommitId, newFiles);
+
+ FileDiffOutput diffOutput =
+ diffOperations.getModifiedFileAgainstParent(
+ testProjectName, newCommitId, /* parentNum=*/ null, fileName2, /* whitespace=*/ null);
+
+ assertThat(diffOutput.oldCommitId()).isEqualTo(oldCommitId);
+ assertThat(diffOutput.newCommitId()).isEqualTo(newCommitId);
+ assertThat(diffOutput.comparisonType().isAgainstParent()).isTrue();
+ assertThat(diffOutput.edits()).hasSize(1);
+ }
+
+ private ObjectId createCommit(
+ Repository repo, ObjectId parentCommit, ImmutableMap<String, String> fileNameToContent)
+ throws IOException {
+ ObjectId treeId = createTree(repo, fileNameToContent);
+ return createCommitInRepo(repo, treeId, parentCommit);
+ }
+
+ private static ObjectId createCommitInRepo(
+ Repository repo, ObjectId treeId, ObjectId parentCommit) throws IOException {
+ try (ObjectInserter oi = repo.newObjectInserter()) {
+ PersonIdent committer =
+ new PersonIdent(new PersonIdent("Foo Bar", "foo.bar@baz.com"), TimeUtil.nowTs());
+ CommitBuilder cb = new CommitBuilder();
+ cb.setTreeId(treeId);
+ cb.setCommitter(committer);
+ cb.setAuthor(committer);
+ cb.setMessage("Test commit");
+ if (parentCommit != null) {
+ cb.setParentIds(parentCommit);
+ }
+ ObjectId commitId = oi.insert(cb);
+ oi.flush();
+ oi.close();
+ return commitId;
+ }
+ }
+
+ private static ObjectId createTree(
+ Repository repo, ImmutableMap<String, String> fileNameToContent) throws IOException {
+ try (ObjectInserter oi = repo.newObjectInserter();
+ ObjectReader reader = repo.newObjectReader();
+ RevWalk rw = new RevWalk(reader); ) {
+ TreeFormatter formatter = new TreeFormatter();
+ for (Map.Entry<String, String> entry : fileNameToContent.entrySet()) {
+ String fileName = entry.getKey();
+ String fileContent = entry.getValue();
+ ObjectId fileObjId = createBlob(repo, fileContent);
+ formatter.append(fileName, rw.lookupBlob(fileObjId));
+ }
+ ObjectId treeId = oi.insert(formatter);
+ oi.flush();
+ oi.close();
+ return treeId;
+ }
+ }
+
+ private static ObjectId createBlob(Repository repo, String content) throws IOException {
+ try (ObjectInserter oi = repo.newObjectInserter()) {
+ ObjectId blobId = oi.insert(Constants.OBJ_BLOB, content.getBytes(UTF_8));
+ oi.flush();
+ oi.close();
+ return blobId;
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java b/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java
new file mode 100644
index 0000000..9ec1625
--- /dev/null
+++ b/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java
@@ -0,0 +1,84 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.permissions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.gerrit.entities.AccessSection;
+import com.google.gerrit.server.permissions.SectionSortCache.EntryKey;
+import com.google.gerrit.server.permissions.SectionSortCache.EntryVal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Test for {@link SectionSortCache} */
+public class SectionSortCacheTest {
+ private SectionSortCache sectionSortCache;
+ private Cache<EntryKey, EntryVal> cache;
+
+ private static final AccessSection sectionA = AccessSection.create("refs/heads/branch_1");
+ private static final AccessSection sectionB = AccessSection.create("refs/base/branch_2");
+ private static final String REF_BASE = "refs/base";
+
+ @Before
+ public void setup() {
+ cache = CacheBuilder.newBuilder().build();
+ sectionSortCache = new SectionSortCache(cache);
+ }
+
+ @Test
+ public void sortSingleElement() {
+ List<AccessSection> input = new ArrayList<>();
+ input.add(sectionA);
+ sectionSortCache.sort(REF_BASE, input);
+ assertThat(input).containsExactly(sectionA);
+ }
+
+ @Test
+ public void sortMultiElements() {
+ List<AccessSection> input = new ArrayList<>();
+ input.add(sectionA);
+ input.add(sectionB);
+ sectionSortCache.sort(REF_BASE, input);
+ assertThat(input).containsExactly(sectionB, sectionA).inOrder();
+ }
+
+ @Test
+ public void sortMultiElementsWhenAlreadyOrdered() {
+ List<AccessSection> input = new ArrayList<>();
+ input.add(sectionB);
+ input.add(sectionA);
+ sectionSortCache.sort(REF_BASE, input);
+ assertThat(input).containsExactly(sectionB, sectionA).inOrder();
+ }
+
+ @Test
+ public void sortMultiElementsWithDuplicates() {
+ AccessSection sectionAClone = sectionA.toBuilder().build();
+ AccessSection sectionBClone = sectionB.toBuilder().build();
+ AccessSection[] input = {sectionBClone, sectionA, sectionAClone, sectionA, sectionB};
+ List<AccessSection> sorted = Arrays.asList(input);
+ sectionSortCache.sort(REF_BASE, sorted);
+ // Cache preserves relative order (reference equality) for identical elements
+ AccessSection[] expected = {sectionBClone, sectionB, sectionA, sectionAClone, sectionA};
+ for (int i = 0; i < sorted.size(); i++) {
+ assert (sorted.get(i) == expected[i]);
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 575fbba..de9c0a5 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.TruthJUnit.assume;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
@@ -705,6 +706,23 @@
}
@Test
+ public void byProjectWithHidden() throws Exception {
+ TestRepository<Repo> hiddenProject = createProject("hiddenProject");
+ insert(hiddenProject, newChange(hiddenProject));
+ projectOperations
+ .project(Project.nameKey("hiddenProject"))
+ .forUpdate()
+ .add(block(Permission.READ).ref("refs/*").group(REGISTERED_USERS))
+ .update();
+
+ TestRepository<Repo> visibleProject = createProject("visibleProject");
+ Change visibleChange = insert(visibleProject, newChange(visibleProject));
+ assertQuery("project:visibleProject", visibleChange);
+ assertQuery("project:hiddenProject");
+ assertQuery("project:visibleProject OR project:hiddenProject", visibleChange);
+ }
+
+ @Test
public void byParentOf() throws Exception {
TestRepository<Repo> repo1 = createProject("repo1");
RevCommit commit1 = repo1.parseBody(repo1.commit().message("message").create());
@@ -2396,21 +2414,24 @@
TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = repo.parseBody(repo.commit().add("file1", "contents1").create());
RevCommit commit2 = repo.parseBody(repo.commit().add("file1", "contents2").create());
+ RevCommit commit3 =
+ repo.parseBody(repo.commit().parent(commit2).add("file1", "contents3").create());
Change change1 = insert(repo, newChangeForCommit(repo, commit1));
Change change2 = insert(repo, newChangeForCommit(repo, commit2));
+ Change change3 = insert(repo, newChangeForCommit(repo, commit3));
RevCommit mergeCommit =
repo.branch("master")
.commit()
.message("Merge commit")
.parent(commit1)
- .parent(commit2)
+ .parent(commit3)
.insertChangeId()
.create();
Change mergeChange = insert(repo, newChangeForCommit(repo, mergeCommit));
assertQuery("status:open is:merge", mergeChange);
- assertQuery("status:open -is:merge", change2, change1);
- assertQuery("status:open", mergeChange, change2, change1);
+ assertQuery("status:open -is:merge", change3, change2, change1);
+ assertQuery("status:open", mergeChange, change3, change2, change1);
}
@Test
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index d80eac0..d760003 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -24,6 +24,7 @@
import com.google.common.base.CharMatcher;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.accounts.AccountInput;
import com.google.gerrit.extensions.api.groups.GroupInput;
@@ -47,7 +48,6 @@
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.group.db.InternalGroupUpdate;
import com.google.gerrit.server.index.group.GroupField;
diff --git a/lib/BUILD b/lib/BUILD
index 0110047..f924e4c 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -54,6 +54,16 @@
)
java_library(
+ name = "jgit-ssh-apache",
+ data = ["//lib:LICENSE-jgit"],
+ visibility = ["//visibility:public"],
+ exports = ["@jgit//org.eclipse.jgit.ssh.apache:ssh-apache"],
+ runtime_deps = [
+ "//lib/mina:sshd-sftp",
+ ],
+)
+
+java_library(
name = "jgit-archive",
data = ["//lib:LICENSE-jgit"],
visibility = ["//visibility:public"],
diff --git a/lib/highlightjs/highlight.min.js b/lib/highlightjs/highlight.min.js
index 38fa024..458cb0c 100644
--- a/lib/highlightjs/highlight.min.js
+++ b/lib/highlightjs/highlight.min.js
@@ -1,5 +1,5 @@
/*
- Highlight.js 10.6.0 (eb122d3b)
+ Highlight.js 10.6.0 (d24895f4)
License: BSD-3-Clause
Copyright (c) 2006-2020, Ivan Sagalaev
*/
@@ -7,19 +7,19 @@
return t instanceof Map?t.clear=t.delete=t.set=()=>{
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
throw Error("set is read-only")
-}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{var s=t[n]
-;"object"!=typeof s||Object.isFrozen(s)||e(s)})),t}var t=e,n=e;t.default=n
-;class s{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
+}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{var i=t[n]
+;"object"!=typeof i||Object.isFrozen(i)||e(i)})),t}var t=e,n=e;t.default=n
+;class i{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}
ignoreMatch(){this.ignore=!0}}function r(e){
return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")
-}function a(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
-;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const i=e=>!!e.kind
-;class o{constructor(e,t){
+}function s(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
+;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const a=e=>!!e.kind
+;class l{constructor(e,t){
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
-this.buffer+=r(e)}openNode(e){if(!i(e))return;let t=e.kind
+this.buffer+=r(e)}openNode(e){if(!a(e))return;let t=e.kind
;e.sublanguage||(t=`${this.classPrefix}${t}`),this.span(t)}closeNode(e){
-i(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
-this.buffer+=`<span class="${e}">`}}class l{constructor(){this.rootNode={
+a(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
+this.buffer+=`<span class="${e}">`}}class o{constructor(){this.rootNode={
children:[]},this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const t={kind:e,children:[]}
@@ -30,79 +30,78 @@
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
-l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e}
+o._collapse(e)})))}}class c extends o{constructor(e){super(),this.options=e}
addKeyword(e,t){""!==e&&(this.openNode(t),this.addText(e),this.closeNode())}
addText(e){""!==e&&this.add(e)}addSublanguage(e,t){const n=e.root
;n.kind=t,n.sublanguage=!0,this.add(n)}toHTML(){
-return new o(this,this.options).value()}finalize(){return!0}}function u(e){
+return new l(this,this.options).value()}finalize(){return!0}}function g(e){
return e?"string"==typeof e?e:e.source:null}
-const g="[a-zA-Z]\\w*",d="[a-zA-Z_]\\w*",h="\\b\\d+(\\.\\d+)?",f="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",p="\\b(0b[01]+)",m={
-begin:"\\\\[\\s\\S]",relevance:0},b={className:"string",begin:"'",end:"'",
-illegal:"\\n",contains:[m]},x={className:"string",begin:'"',end:'"',
-illegal:"\\n",contains:[m]},E={
+const u=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,d="[a-zA-Z]\\w*",h="[a-zA-Z_]\\w*",f="\\b\\d+(\\.\\d+)?",p="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",m="\\b(0b[01]+)",b={
+begin:"\\\\[\\s\\S]",relevance:0},E={className:"string",begin:"'",end:"'",
+illegal:"\\n",contains:[b]},x={className:"string",begin:'"',end:'"',
+illegal:"\\n",contains:[b]},v={
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
-},v=(e,t,n={})=>{const s=a({className:"comment",begin:e,end:t,contains:[]},n)
-;return s.contains.push(E),s.contains.push({className:"doctag",
-begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),s
-},w=v("//","$"),N=v("/\\*","\\*/"),y=v("#","$");var R=Object.freeze({
-__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:g,UNDERSCORE_IDENT_RE:d,
-NUMBER_RE:h,C_NUMBER_RE:f,BINARY_NUMBER_RE:p,
+},w=(e,t,n={})=>{const i=s({className:"comment",begin:e,end:t,contains:[]},n)
+;return i.contains.push(v),i.contains.push({className:"doctag",
+begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),i
+},y=w("//","$"),N=w("/\\*","\\*/"),R=w("#","$");var _=Object.freeze({
+__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:d,UNDERSCORE_IDENT_RE:h,
+NUMBER_RE:f,C_NUMBER_RE:p,BINARY_NUMBER_RE:m,
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const t=/^#![ ]*\//
-;return e.binary&&(e.begin=((...e)=>e.map((e=>u(e))).join(""))(t,/.*\b/,e.binary,/\b.*/)),
-a({className:"meta",begin:t,end:/$/,relevance:0,"on:begin":(e,t)=>{
-0!==e.index&&t.ignoreMatch()}},e)},BACKSLASH_ESCAPE:m,APOS_STRING_MODE:b,
-QUOTE_STRING_MODE:x,PHRASAL_WORDS_MODE:E,COMMENT:v,C_LINE_COMMENT_MODE:w,
-C_BLOCK_COMMENT_MODE:N,HASH_COMMENT_MODE:y,NUMBER_MODE:{className:"number",
-begin:h,relevance:0},C_NUMBER_MODE:{className:"number",begin:f,relevance:0},
-BINARY_NUMBER_MODE:{className:"number",begin:p,relevance:0},CSS_NUMBER_MODE:{
+;return e.binary&&(e.begin=((...e)=>e.map((e=>g(e))).join(""))(t,/.*\b/,e.binary,/\b.*/)),
+s({className:"meta",begin:t,end:/$/,relevance:0,"on:begin":(e,t)=>{
+0!==e.index&&t.ignoreMatch()}},e)},BACKSLASH_ESCAPE:b,APOS_STRING_MODE:E,
+QUOTE_STRING_MODE:x,PHRASAL_WORDS_MODE:v,COMMENT:w,C_LINE_COMMENT_MODE:y,
+C_BLOCK_COMMENT_MODE:N,HASH_COMMENT_MODE:R,NUMBER_MODE:{className:"number",
+begin:f,relevance:0},C_NUMBER_MODE:{className:"number",begin:p,relevance:0},
+BINARY_NUMBER_MODE:{className:"number",begin:m,relevance:0},CSS_NUMBER_MODE:{
className:"number",
-begin:h+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
+begin:f+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",
-begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[m,{begin:/\[/,end:/\]/,
-relevance:0,contains:[m]}]}]},TITLE_MODE:{className:"title",begin:g,relevance:0
-},UNDERSCORE_TITLE_MODE:{className:"title",begin:d,relevance:0},METHOD_GUARD:{
+begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[b,{begin:/\[/,end:/\]/,
+relevance:0,contains:[b]}]}]},TITLE_MODE:{className:"title",begin:d,relevance:0
+},UNDERSCORE_TITLE_MODE:{className:"title",begin:h,relevance:0},METHOD_GUARD:{
begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
-t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function _(e,t){
-"."===e.input[e.index-1]&&t.ignoreMatch()}function k(e,t){
+t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function k(e,t){
+"."===e.input[e.index-1]&&t.ignoreMatch()}function O(e,t){
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
-e.__beforeBegin=_,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
-void 0===e.relevance&&(e.relevance=0))}function O(e,t){
-Array.isArray(e.illegal)&&(e.illegal=((...e)=>"("+e.map((e=>u(e))).join("|")+")")(...e.illegal))
-}function M(e,t){if(e.match){
+e.__beforeBegin=k,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
+void 0===e.relevance&&(e.relevance=0))}function M(e,t){
+Array.isArray(e.illegal)&&(e.illegal=((...e)=>"("+e.map((e=>g(e))).join("|")+")")(...e.illegal))
+}function A(e,t){if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
-;e.begin=e.match,delete e.match}}function A(e,t){
+;e.begin=e.match,delete e.match}}function L(e,t){
void 0===e.relevance&&(e.relevance=1)}
-const L=["of","and","for","in","not","or","if","then","parent","list","value"]
-;function B(e,t,n="keyword"){const s={}
+const j=["of","and","for","in","not","or","if","then","parent","list","value"]
+;function B(e,t,n="keyword"){const i={}
;return"string"==typeof e?r(n,e.split(" ")):Array.isArray(e)?r(n,e):Object.keys(e).forEach((n=>{
-Object.assign(s,B(e[n],t,n))})),s;function r(e,n){
+Object.assign(i,B(e[n],t,n))})),i;function r(e,n){
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
-;s[n[0]]=[e,I(n[0],n[1])]}))}}function I(e,t){
-return t?Number(t):(e=>L.includes(e.toLowerCase()))(e)?0:1}
+;i[n[0]]=[e,I(n[0],n[1])]}))}}function I(e,t){
+return t?Number(t):(e=>j.includes(e.toLowerCase()))(e)?0:1}
function T(e,{plugins:t}){function n(t,n){
-return RegExp(u(t),"m"+(e.case_insensitive?"i":"")+(n?"g":""))}class s{
+return RegExp(g(t),"m"+(e.case_insensitive?"i":"")+(n?"g":""))}class i{
constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,t){
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
this.matchAt+=(e=>RegExp(e.toString()+"|").exec("").length-1)(e)+1}compile(){
0===this.regexes.length&&(this.exec=()=>null)
-;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(((e,t="|")=>{
-const n=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;let s=0,r=""
-;for(let a=0;a<e.length;a++){s+=1;const i=s;let o=u(e[a])
-;for(a>0&&(r+=t),r+="(";o.length>0;){const e=n.exec(o);if(null==e){r+=o;break}
-r+=o.substring(0,e.index),
-o=o.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+i):(r+=e[0],
-"("===e[0]&&s++)}r+=")"}return r})(e),!0),this.lastIndex=0}exec(e){
+;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(((e,t="|")=>{let n=0
+;return e.map((e=>{n+=1;const t=n;let i=g(e),r="";for(;i.length>0;){
+const e=u.exec(i);if(!e){r+=i;break}
+r+=i.substring(0,e.index),i=i.substring(e.index+e[0].length),
+"\\"===e[0][0]&&e[1]?r+="\\"+(Number(e[1])+t):(r+=e[0],"("===e[0]&&n++)}return r
+})).map((e=>`(${e})`)).join(t)})(e),!0),this.lastIndex=0}exec(e){
this.matcherRe.lastIndex=this.lastIndex;const t=this.matcherRe.exec(e)
;if(!t)return null
-;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),s=this.matchIndexes[n]
-;return t.splice(0,n),Object.assign(t,s)}}class r{constructor(){
+;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
+;return t.splice(0,n),Object.assign(t,i)}}class r{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
-if(this.multiRegexes[e])return this.multiRegexes[e];const t=new s
+if(this.multiRegexes[e])return this.multiRegexes[e];const t=new i
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
@@ -115,30 +114,30 @@
this.regexIndex===this.count&&this.considerAll()),n}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
-;return e.classNameAliases=a(e.classNameAliases||{}),function t(s,i){const o=s
-;if(s.compiled)return o
-;[M].forEach((e=>e(s,i))),e.compilerExtensions.forEach((e=>e(s,i))),
-s.__beforeBegin=null,[k,O,A].forEach((e=>e(s,i))),s.compiled=!0;let l=null
-;if("object"==typeof s.keywords&&(l=s.keywords.$pattern,
-delete s.keywords.$pattern),
-s.keywords&&(s.keywords=B(s.keywords,e.case_insensitive)),
-s.lexemes&&l)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ")
-;return l=l||s.lexemes||/\w+/,
-o.keywordPatternRe=n(l,!0),i&&(s.begin||(s.begin=/\B|\b/),
-o.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),
-s.end||s.endsWithParent||(s.end=/\B|\b/),
-s.end&&(o.endRe=n(s.end)),o.terminatorEnd=u(s.end)||"",
-s.endsWithParent&&i.terminatorEnd&&(o.terminatorEnd+=(s.end?"|":"")+i.terminatorEnd)),
-s.illegal&&(o.illegalRe=n(s.illegal)),
-s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>a(e,{
-variants:null},t)))),e.cachedVariants?e.cachedVariants:j(e)?a(e,{
-starts:e.starts?a(e.starts):null
-}):Object.isFrozen(e)?a(e):e))("self"===e?s:e)))),s.contains.forEach((e=>{t(e,o)
-})),s.starts&&t(s.starts,i),o.matcher=(e=>{const t=new r
+;return e.classNameAliases=s(e.classNameAliases||{}),function t(i,a){const l=i
+;if(i.compiled)return l
+;[A].forEach((e=>e(i,a))),e.compilerExtensions.forEach((e=>e(i,a))),
+i.__beforeBegin=null,[O,M,L].forEach((e=>e(i,a))),i.compiled=!0;let o=null
+;if("object"==typeof i.keywords&&(o=i.keywords.$pattern,
+delete i.keywords.$pattern),
+i.keywords&&(i.keywords=B(i.keywords,e.case_insensitive)),
+i.lexemes&&o)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ")
+;return o=o||i.lexemes||/\w+/,
+l.keywordPatternRe=n(o,!0),a&&(i.begin||(i.begin=/\B|\b/),
+l.beginRe=n(i.begin),i.endSameAsBegin&&(i.end=i.begin),
+i.end||i.endsWithParent||(i.end=/\B|\b/),
+i.end&&(l.endRe=n(i.end)),l.terminatorEnd=g(i.end)||"",
+i.endsWithParent&&a.terminatorEnd&&(l.terminatorEnd+=(i.end?"|":"")+a.terminatorEnd)),
+i.illegal&&(l.illegalRe=n(i.illegal)),
+i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>s(e,{
+variants:null},t)))),e.cachedVariants?e.cachedVariants:S(e)?s(e,{
+starts:e.starts?s(e.starts):null
+}):Object.isFrozen(e)?s(e):e))("self"===e?i:e)))),i.contains.forEach((e=>{t(e,l)
+})),i.starts&&t(i.starts,a),l.matcher=(e=>{const t=new r
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
-}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(o),o}(e)}function j(e){
-return!!e&&(e.endsWithParent||j(e.starts))}function S(e){const t={
+}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(l),l}(e)}function S(e){
+return!!e&&(e.endsWithParent||S(e.starts))}function P(e){const t={
props:["language","code","autodetect"],data:()=>({detectedLanguage:"",
unknownLanguage:!1}),computed:{className(){
return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){
@@ -150,149 +149,157 @@
return!(this.language&&(e=this.autodetect,!e&&""!==e));var e},
ignoreIllegals:()=>!0},render(e){return e("pre",{},[e("code",{
class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{
-Component:t,VuePlugin:{install(e){e.component("highlightjs",t)}}}}const P={
-"after:highlightBlock":({block:e,result:t,text:n})=>{const s=C(e)
-;if(!s.length)return;const a=document.createElement("div")
-;a.innerHTML=t.value,t.value=((e,t,n)=>{let s=0,a="";const i=[];function o(){
+Component:t,VuePlugin:{install(e){e.component("highlightjs",t)}}}}const D={
+"after:highlightElement":({el:e,result:t,text:n})=>{const i=H(e)
+;if(!i.length)return;const s=document.createElement("div")
+;s.innerHTML=t.value,t.value=((e,t,n)=>{let i=0,s="";const a=[];function l(){
return e.length&&t.length?e[0].offset!==t[0].offset?e[0].offset<t[0].offset?e:t:"start"===t[0].event?e:t:e.length?e:t
-}function l(e){a+="<"+D(e)+[].map.call(e.attributes,(function(e){
+}function o(e){s+="<"+C(e)+[].map.call(e.attributes,(function(e){
return" "+e.nodeName+'="'+r(e.value)+'"'})).join("")+">"}function c(e){
-a+="</"+D(e)+">"}function u(e){("start"===e.event?l:c)(e.node)}
-for(;e.length||t.length;){let t=o()
-;if(a+=r(n.substring(s,t[0].offset)),s=t[0].offset,t===e){i.reverse().forEach(c)
-;do{u(t.splice(0,1)[0]),t=o()}while(t===e&&t.length&&t[0].offset===s)
-;i.reverse().forEach(l)
-}else"start"===t[0].event?i.push(t[0].node):i.pop(),u(t.splice(0,1)[0])}
-return a+r(n.substr(s))})(s,C(a),n)}};function D(e){
-return e.nodeName.toLowerCase()}function C(e){const t=[];return function e(n,s){
-for(let r=n.firstChild;r;r=r.nextSibling)3===r.nodeType?s+=r.nodeValue.length:1===r.nodeType&&(t.push({
-event:"start",offset:s,node:r}),s=e(r,s),D(r).match(/br|hr|img|input/)||t.push({
-event:"stop",offset:s,node:r}));return s}(e,0),t}const H=e=>{console.error(e)
-},U=(e,...t)=>{console.log("WARN: "+e,...t)},$=(e,t)=>{
-console.log(`Deprecated as of ${e}. ${t}`)},z=r,K=a,G=Symbol("nomatch")
-;return(e=>{const n=Object.create(null),r=Object.create(null),a=[];let i=!0
-;const o=/(^(<[^>]+>|\t|)+|\n)/gm,l="Could not find the language '{}', did you forget to load/include a language module?",u={
-disableAutodetect:!0,name:"Plain text",contains:[]};let g={
+s+="</"+C(e)+">"}function g(e){("start"===e.event?o:c)(e.node)}
+for(;e.length||t.length;){let t=l()
+;if(s+=r(n.substring(i,t[0].offset)),i=t[0].offset,t===e){a.reverse().forEach(c)
+;do{g(t.splice(0,1)[0]),t=l()}while(t===e&&t.length&&t[0].offset===i)
+;a.reverse().forEach(o)
+}else"start"===t[0].event?a.push(t[0].node):a.pop(),g(t.splice(0,1)[0])}
+return s+r(n.substr(i))})(i,H(s),n)}};function C(e){
+return e.nodeName.toLowerCase()}function H(e){const t=[];return function e(n,i){
+for(let r=n.firstChild;r;r=r.nextSibling)3===r.nodeType?i+=r.nodeValue.length:1===r.nodeType&&(t.push({
+event:"start",offset:i,node:r}),i=e(r,i),C(r).match(/br|hr|img|input/)||t.push({
+event:"stop",offset:i,node:r}));return i}(e,0),t}const $=e=>{console.error(e)
+},U=(e,...t)=>{console.log("WARN: "+e,...t)},z=(e,t)=>{
+console.log(`Deprecated as of ${e}. ${t}`)},K=r,G=s,V=Symbol("nomatch")
+;return(e=>{const n=Object.create(null),r=Object.create(null),s=[];let a=!0
+;const l=/(^(<[^>]+>|\t|)+|\n)/gm,o="Could not find the language '{}', did you forget to load/include a language module?",g={
+disableAutodetect:!0,name:"Plain text",contains:[]};let u={
noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
tabReplace:null,useBR:!1,languages:null,__emitter:c};function d(e){
-return g.noHighlightRe.test(e)}function h(e,t,n,s){const r={code:t,language:e}
-;M("before:highlight",r);const a=r.result?r.result:f(r.language,r.code,n,s)
-;return a.code=r.code,M("after:highlight",a),a}function f(e,t,r,o){const c=t
-;function u(e,t){const n=w.case_insensitive?t[0].toLowerCase():t[0]
+return u.noHighlightRe.test(e)}function h(e,t,n,i){const r={code:t,language:e}
+;M("before:highlight",r);const s=r.result?r.result:f(r.language,r.code,n,i)
+;return s.code=r.code,M("after:highlight",s),s}function f(e,t,r,l){const c=t
+;function g(e,t){const n=w.case_insensitive?t[0].toLowerCase():t[0]
;return Object.prototype.hasOwnProperty.call(e.keywords,n)&&e.keywords[n]}
-function d(){null!=R.subLanguage?(()=>{if(""===M)return;let e=null
-;if("string"==typeof R.subLanguage){
-if(!n[R.subLanguage])return void O.addText(M)
-;e=f(R.subLanguage,M,!0,k[R.subLanguage]),k[R.subLanguage]=e.top
-}else e=p(M,R.subLanguage.length?R.subLanguage:null)
-;R.relevance>0&&(A+=e.relevance),O.addSublanguage(e.emitter,e.language)
-})():(()=>{if(!R.keywords)return void O.addText(M);let e=0
-;R.keywordPatternRe.lastIndex=0;let t=R.keywordPatternRe.exec(M),n="";for(;t;){
-n+=M.substring(e,t.index);const s=u(R,t);if(s){const[e,r]=s
-;O.addText(n),n="",A+=r;const a=w.classNameAliases[e]||e;O.addKeyword(t[0],a)
-}else n+=t[0];e=R.keywordPatternRe.lastIndex,t=R.keywordPatternRe.exec(M)}
+function d(){null!=_.subLanguage?(()=>{if(""===M)return;let e=null
+;if("string"==typeof _.subLanguage){
+if(!n[_.subLanguage])return void O.addText(M)
+;e=f(_.subLanguage,M,!0,k[_.subLanguage]),k[_.subLanguage]=e.top
+}else e=p(M,_.subLanguage.length?_.subLanguage:null)
+;_.relevance>0&&(A+=e.relevance),O.addSublanguage(e.emitter,e.language)
+})():(()=>{if(!_.keywords)return void O.addText(M);let e=0
+;_.keywordPatternRe.lastIndex=0;let t=_.keywordPatternRe.exec(M),n="";for(;t;){
+n+=M.substring(e,t.index);const i=g(_,t);if(i){const[e,r]=i
+;O.addText(n),n="",A+=r;const s=w.classNameAliases[e]||e;O.addKeyword(t[0],s)
+}else n+=t[0];e=_.keywordPatternRe.lastIndex,t=_.keywordPatternRe.exec(M)}
n+=M.substr(e),O.addText(n)})(),M=""}function h(e){
return e.className&&O.openNode(w.classNameAliases[e.className]||e.className),
-R=Object.create(e,{parent:{value:R}}),R}function m(e,t,n){let r=((e,t)=>{
+_=Object.create(e,{parent:{value:_}}),_}function m(e,t,n){let r=((e,t)=>{
const n=e&&e.exec(t);return n&&0===n.index})(e.endRe,n);if(r){if(e["on:end"]){
-const n=new s(e);e["on:end"](t,n),n.ignore&&(r=!1)}if(r){
+const n=new i(e);e["on:end"](t,n),n.ignore&&(r=!1)}if(r){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return m(e.parent,t,n)}function b(e){
-return 0===R.matcher.regexIndex?(M+=e[0],1):(I=!0,0)}function x(e){
-const t=e[0],n=c.substr(e.index),s=m(R,e,n);if(!s)return G;const r=R
+return 0===_.matcher.regexIndex?(M+=e[0],1):(B=!0,0)}function E(e){
+const t=e[0],n=c.substr(e.index),i=m(_,e,n);if(!i)return V;const r=_
;r.skip?M+=t:(r.returnEnd||r.excludeEnd||(M+=t),d(),r.excludeEnd&&(M=t));do{
-R.className&&O.closeNode(),R.skip||R.subLanguage||(A+=R.relevance),R=R.parent
-}while(R!==s.parent)
-;return s.starts&&(s.endSameAsBegin&&(s.starts.endRe=s.endRe),
-h(s.starts)),r.returnEnd?0:t.length}let E={};function v(t,n){const a=n&&n[0]
-;if(M+=t,null==a)return d(),0
-;if("begin"===E.type&&"end"===n.type&&E.index===n.index&&""===a){
-if(M+=c.slice(n.index,n.index+1),!i){const t=Error("0 width match regex")
-;throw t.languageName=e,t.badRule=E.rule,t}return 1}
-if(E=n,"begin"===n.type)return function(e){
-const t=e[0],n=e.rule,r=new s(n),a=[n.__beforeBegin,n["on:begin"]]
-;for(const n of a)if(n&&(n(e,r),r.ignore))return b(t)
+_.className&&O.closeNode(),_.skip||_.subLanguage||(A+=_.relevance),_=_.parent
+}while(_!==i.parent)
+;return i.starts&&(i.endSameAsBegin&&(i.starts.endRe=i.endRe),
+h(i.starts)),r.returnEnd?0:t.length}let x={};function v(t,n){const s=n&&n[0]
+;if(M+=t,null==s)return d(),0
+;if("begin"===x.type&&"end"===n.type&&x.index===n.index&&""===s){
+if(M+=c.slice(n.index,n.index+1),!a){const t=Error("0 width match regex")
+;throw t.languageName=e,t.badRule=x.rule,t}return 1}
+if(x=n,"begin"===n.type)return function(e){
+const t=e[0],n=e.rule,r=new i(n),s=[n.__beforeBegin,n["on:begin"]]
+;for(const n of s)if(n&&(n(e,r),r.ignore))return b(t)
;return n&&n.endSameAsBegin&&(n.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),
n.skip?M+=t:(n.excludeBegin&&(M+=t),
d(),n.returnBegin||n.excludeBegin||(M=t)),h(n),n.returnBegin?0:t.length}(n)
;if("illegal"===n.type&&!r){
-const e=Error('Illegal lexeme "'+a+'" for mode "'+(R.className||"<unnamed>")+'"')
-;throw e.mode=R,e}if("end"===n.type){const e=x(n);if(e!==G)return e}
-if("illegal"===n.type&&""===a)return 1
-;if(B>1e5&&B>3*n.index)throw Error("potential infinite loop, way more iterations than matches")
-;return M+=a,a.length}const w=_(e)
-;if(!w)throw H(l.replace("{}",e)),Error('Unknown language: "'+e+'"')
-;const N=T(w,{plugins:a});let y="",R=o||N;const k={},O=new g.__emitter(g);(()=>{
-const e=[];for(let t=R;t!==w;t=t.parent)t.className&&e.unshift(t.className)
-;e.forEach((e=>O.openNode(e)))})();let M="",A=0,L=0,B=0,I=!1;try{
-for(R.matcher.considerAll();;){
-B++,I?I=!1:R.matcher.considerAll(),R.matcher.lastIndex=L
-;const e=R.matcher.exec(c);if(!e)break;const t=v(c.substring(L,e.index),e)
-;L=e.index+t}return v(c.substr(L)),O.closeAllNodes(),O.finalize(),y=O.toHTML(),{
-relevance:Math.floor(A),value:y,language:e,illegal:!1,emitter:O,top:R}}catch(t){
+const e=Error('Illegal lexeme "'+s+'" for mode "'+(_.className||"<unnamed>")+'"')
+;throw e.mode=_,e}if("end"===n.type){const e=E(n);if(e!==V)return e}
+if("illegal"===n.type&&""===s)return 1
+;if(j>1e5&&j>3*n.index)throw Error("potential infinite loop, way more iterations than matches")
+;return M+=s,s.length}const w=R(e)
+;if(!w)throw $(o.replace("{}",e)),Error('Unknown language: "'+e+'"')
+;const y=T(w,{plugins:s});let N="",_=l||y;const k={},O=new u.__emitter(u);(()=>{
+const e=[];for(let t=_;t!==w;t=t.parent)t.className&&e.unshift(t.className)
+;e.forEach((e=>O.openNode(e)))})();let M="",A=0,L=0,j=0,B=!1;try{
+for(_.matcher.considerAll();;){
+j++,B?B=!1:_.matcher.considerAll(),_.matcher.lastIndex=L
+;const e=_.matcher.exec(c);if(!e)break;const t=v(c.substring(L,e.index),e)
+;L=e.index+t}return v(c.substr(L)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{
+relevance:Math.floor(A),value:N,language:e,illegal:!1,emitter:O,top:_}}catch(t){
if(t.message&&t.message.includes("Illegal"))return{illegal:!0,illegalBy:{
-msg:t.message,context:c.slice(L-100,L+100),mode:t.mode},sofar:y,relevance:0,
-value:z(c),emitter:O};if(i)return{illegal:!1,relevance:0,value:z(c),emitter:O,
-language:e,top:R,errorRaised:t};throw t}}function p(e,t){
-t=t||g.languages||Object.keys(n);const s=(e=>{const t={relevance:0,
-emitter:new g.__emitter(g),value:z(e),illegal:!1,top:u}
-;return t.emitter.addText(e),t})(e),r=t.filter(_).filter(O).map((t=>f(t,e,!1)))
-;r.unshift(s);const a=r.sort(((e,t)=>{
+msg:t.message,context:c.slice(L-100,L+100),mode:t.mode},sofar:N,relevance:0,
+value:K(c),emitter:O};if(a)return{illegal:!1,relevance:0,value:K(c),emitter:O,
+language:e,top:_,errorRaised:t};throw t}}function p(e,t){
+t=t||u.languages||Object.keys(n);const i=(e=>{const t={relevance:0,
+emitter:new u.__emitter(u),value:K(e),illegal:!1,top:g}
+;return t.emitter.addText(e),t})(e),r=t.filter(R).filter(O).map((t=>f(t,e,!1)))
+;r.unshift(i);const s=r.sort(((e,t)=>{
if(e.relevance!==t.relevance)return t.relevance-e.relevance
-;if(e.language&&t.language){if(_(e.language).supersetOf===t.language)return 1
-;if(_(t.language).supersetOf===e.language)return-1}return 0})),[i,o]=a,l=i
-;return l.second_best=o,l}const m={"before:highlightBlock":({block:e})=>{
-g.useBR&&(e.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ /]*>/g,"\n"))
-},"after:highlightBlock":({result:e})=>{
-g.useBR&&(e.value=e.value.replace(/\n/g,"<br>"))}},b=/^(<[^>]+>|\t)+/gm,x={
-"after:highlightBlock":({result:e})=>{
-g.tabReplace&&(e.value=e.value.replace(b,(e=>e.replace(/\t/g,g.tabReplace))))}}
-;function E(e){let t=null;const n=(e=>{let t=e.className+" "
-;t+=e.parentNode?e.parentNode.className:"";const n=g.languageDetectRe.exec(t)
-;if(n){const t=_(n[1])
-;return t||(U(l.replace("{}",n[1])),U("Falling back to no-highlight mode for this block.",e)),
-t?n[1]:"no-highlight"}return t.split(/\s+/).find((e=>d(e)||_(e)))})(e)
-;if(d(n))return;M("before:highlightBlock",{block:e,language:n}),t=e
-;const s=t.textContent,a=n?h(n,s,!0):p(s);M("after:highlightBlock",{block:e,
-result:a,text:s}),e.innerHTML=a.value,((e,t,n)=>{const s=t?r[t]:n
-;e.classList.add("hljs"),s&&e.classList.add(s)})(e,n,a.language),e.result={
-language:a.language,re:a.relevance,relavance:a.relevance
-},a.second_best&&(e.second_best={language:a.second_best.language,
-re:a.second_best.relevance,relavance:a.second_best.relevance})}const v=()=>{
+;if(e.language&&t.language){if(R(e.language).supersetOf===t.language)return 1
+;if(R(t.language).supersetOf===e.language)return-1}return 0})),[a,l]=s,o=a
+;return o.second_best=l,o}const m={"before:highlightElement":({el:e})=>{
+u.useBR&&(e.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ /]*>/g,"\n"))
+},"after:highlightElement":({result:e})=>{
+u.useBR&&(e.value=e.value.replace(/\n/g,"<br>"))}},b=/^(<[^>]+>|\t)+/gm,E={
+"after:highlightElement":({result:e})=>{
+u.tabReplace&&(e.value=e.value.replace(b,(e=>e.replace(/\t/g,u.tabReplace))))}}
+;function x(e){let t=null;const n=(e=>{let t=e.className+" "
+;t+=e.parentNode?e.parentNode.className:"";const n=u.languageDetectRe.exec(t)
+;if(n){const t=R(n[1])
+;return t||(U(o.replace("{}",n[1])),U("Falling back to no-highlight mode for this block.",e)),
+t?n[1]:"no-highlight"}return t.split(/\s+/).find((e=>d(e)||R(e)))})(e)
+;if(d(n))return;M("before:highlightElement",{el:e,language:n}),t=e
+;const i=t.textContent,s=n?h(n,i,!0):p(i);M("after:highlightElement",{el:e,
+result:s,text:i}),e.innerHTML=s.value,((e,t,n)=>{const i=t?r[t]:n
+;e.classList.add("hljs"),i&&e.classList.add(i)})(e,n,s.language),e.result={
+language:s.language,re:s.relevance,relavance:s.relevance
+},s.second_best&&(e.second_best={language:s.second_best.language,
+re:s.second_best.relevance,relavance:s.second_best.relevance})}const v=()=>{
v.called||(v.called=!0,
-$("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead."),
-document.querySelectorAll("pre code").forEach(E))};let w=!1,N=!1;function y(){
-N?document.querySelectorAll("pre code").forEach(E):w=!0}function _(e){
+z("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead."),
+document.querySelectorAll("pre code").forEach(x))};let w=!1,y=!1;function N(){
+y?document.querySelectorAll("pre code").forEach(x):w=!0}function R(e){
return e=(e||"").toLowerCase(),n[e]||n[r[e]]}function k(e,{languageName:t}){
-"string"==typeof e&&(e=[e]),e.forEach((e=>{r[e]=t}))}function O(e){const t=_(e)
-;return t&&!t.disableAutodetect}function M(e,t){const n=e;a.forEach((e=>{
-e[n]&&e[n](t)}))}
+"string"==typeof e&&(e=[e]),e.forEach((e=>{r[e.toLowerCase()]=t}))}
+function O(e){const t=R(e);return t&&!t.disableAutodetect}function M(e,t){
+const n=e;s.forEach((e=>{e[n]&&e[n](t)}))}
"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
-N=!0,w&&y()}),!1),Object.assign(e,{highlight:h,highlightAuto:p,highlightAll:y,
+y=!0,w&&N()}),!1),Object.assign(e,{highlight:h,highlightAuto:p,highlightAll:N,
fixMarkup:e=>{
-return $("10.2.0","fixMarkup will be removed entirely in v11.0"),$("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),
+return z("10.2.0","fixMarkup will be removed entirely in v11.0"),z("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),
t=e,
-g.tabReplace||g.useBR?t.replace(o,(e=>"\n"===e?g.useBR?"<br>":e:g.tabReplace?e.replace(/\t/g,g.tabReplace):e)):t
-;var t},highlightBlock:E,configure:e=>{
-e.useBR&&($("10.3.0","'useBR' will be removed entirely in v11.0"),
-$("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),
-g=K(g,e)},initHighlighting:v,initHighlightingOnLoad:()=>{
-$("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),
-w=!0},registerLanguage:(t,s)=>{let r=null;try{r=s(e)}catch(e){
-if(H("Language definition for '{}' could not be registered.".replace("{}",t)),
-!i)throw e;H(e),r=u}
-r.name||(r.name=t),n[t]=r,r.rawDefinition=s.bind(null,e),r.aliases&&k(r.aliases,{
-languageName:t})},listLanguages:()=>Object.keys(n),getLanguage:_,
-registerAliases:k,requireLanguage:e=>{
-$("10.4.0","requireLanguage will be removed entirely in v11."),
-$("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844")
-;const t=_(e);if(t)return t
+u.tabReplace||u.useBR?t.replace(l,(e=>"\n"===e?u.useBR?"<br>":e:u.tabReplace?e.replace(/\t/g,u.tabReplace):e)):t
+;var t},highlightElement:x,
+highlightBlock:e=>(z("10.7.0","highlightBlock will be removed entirely in v12.0"),
+z("10.7.0","Please use highlightElement now."),x(e)),configure:e=>{
+e.useBR&&(z("10.3.0","'useBR' will be removed entirely in v11.0"),
+z("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),
+u=G(u,e)},initHighlighting:v,initHighlightingOnLoad:()=>{
+z("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),
+w=!0},registerLanguage:(t,i)=>{let r=null;try{r=i(e)}catch(e){
+if($("Language definition for '{}' could not be registered.".replace("{}",t)),
+!a)throw e;$(e),r=g}
+r.name||(r.name=t),n[t]=r,r.rawDefinition=i.bind(null,e),r.aliases&&k(r.aliases,{
+languageName:t})},unregisterLanguage:e=>{delete n[e]
+;for(const t of Object.keys(r))r[t]===e&&delete r[t]},
+listLanguages:()=>Object.keys(n),getLanguage:R,registerAliases:k,
+requireLanguage:e=>{
+z("10.4.0","requireLanguage will be removed entirely in v11."),
+z("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844")
+;const t=R(e);if(t)return t
;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},
-autoDetection:O,inherit:K,addPlugin:e=>{a.push(e)},vuePlugin:S(e).VuePlugin
-}),e.debugMode=()=>{i=!1},e.safeMode=()=>{i=!0},e.versionString="10.6.0"
-;for(const e in R)"object"==typeof R[e]&&t(R[e])
-;return Object.assign(e,R),e.addPlugin(m),e.addPlugin(P),e.addPlugin(x),e})({})
+autoDetection:O,inherit:G,addPlugin:e=>{(e=>{
+e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
+e["before:highlightBlock"](Object.assign({block:t.el},t))
+}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
+e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),s.push(e)},
+vuePlugin:P(e).VuePlugin}),e.debugMode=()=>{a=!1},e.safeMode=()=>{a=!0
+},e.versionString="10.6.0";for(const e in _)"object"==typeof _[e]&&t(_[e])
+;return Object.assign(e,_),e.addPlugin(m),e.addPlugin(D),e.addPlugin(E),e})({})
}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);
hljs.registerLanguage("1c",(()=>{"use strict";return s=>{
var x="[A-Za-z\u0410-\u042f\u0430-\u044f\u0451\u0401_][A-Za-z\u0410-\u042f\u0430-\u044f\u0451\u0401_0-9]+",n="\u0434\u0430\u043b\u0435\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u043b\u044f \u0435\u0441\u043b\u0438 \u0438 \u0438\u0437 \u0438\u043b\u0438 \u0438\u043d\u0430\u0447\u0435 \u0438\u043d\u0430\u0447\u0435\u0435\u0441\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u0435\u0446\u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0435\u0446\u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043a\u043e\u043d\u0435\u0446\u0446\u0438\u043a\u043b\u0430 \u043d\u0435 \u043d\u043e\u0432\u044b\u0439 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u0435\u0440\u0435\u043c \u043f\u043e \u043f\u043e\u043a\u0430 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u0440\u0435\u0440\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0442\u043e\u0433\u0434\u0430 \u0446\u0438\u043a\u043b \u044d\u043a\u0441\u043f\u043e\u0440\u0442 ",e="null \u0438\u0441\u0442\u0438\u043d\u0430 \u043b\u043e\u0436\u044c \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e",o=s.inherit(s.NUMBER_MODE),t={
@@ -492,11 +499,11 @@
relevance:0},g={className:"function",begin:"("+i+"[\\*&\\s]+)+"+d,
returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:u,illegal:/[^\w\s\*&:<>.]/,
contains:[{begin:"decltype\\(auto\\)",keywords:u,relevance:0},{begin:d,
-returnBegin:!0,contains:[c],relevance:0},{className:"params",begin:/\(/,
-end:/\)/,keywords:u,relevance:0,contains:[r,t.C_BLOCK_COMMENT_MODE,s,o,a,{
-begin:/\(/,end:/\)/,keywords:u,relevance:0,
-contains:["self",r,t.C_BLOCK_COMMENT_MODE,s,o,a]}]
-},a,r,t.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",
+returnBegin:!0,contains:[c],relevance:0},{begin:/::/,relevance:0},{begin:/:/,
+endsWithParent:!0,contains:[s,o]},{className:"params",begin:/\(/,end:/\)/,
+keywords:u,relevance:0,contains:[r,t.C_BLOCK_COMMENT_MODE,s,o,a,{begin:/\(/,
+end:/\)/,keywords:u,relevance:0,contains:["self",r,t.C_BLOCK_COMMENT_MODE,s,o,a]
+}]},a,r,t.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"</",
contains:[].concat(p,g,m,[l,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",
@@ -639,11 +646,11 @@
contains:[{begin:/""/,relevance:0}]},{begin:/'/,end:/'/,contains:[{begin:/''/,
relevance:0}]}]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]};return{
name:"AutoIt",case_insensitive:!0,illegal:/\/\*/,keywords:{
-keyword:"ByRef Case Const ContinueCase ContinueLoop Default Dim Do Else ElseIf EndFunc EndIf EndSelect EndSwitch EndWith Enum Exit ExitLoop For Func Global If In Local Next ReDim Return Select Static Step Switch Then To Until Volatile WEnd While With",
-built_in:"Abs ACos AdlibRegister AdlibUnRegister Asc AscW ASin Assign ATan AutoItSetOption AutoItWinGetTitle AutoItWinSetTitle Beep Binary BinaryLen BinaryMid BinaryToString BitAND BitNOT BitOR BitRotate BitShift BitXOR BlockInput Break Call CDTray Ceiling Chr ChrW ClipGet ClipPut ConsoleRead ConsoleWrite ConsoleWriteError ControlClick ControlCommand ControlDisable ControlEnable ControlFocus ControlGetFocus ControlGetHandle ControlGetPos ControlGetText ControlHide ControlListView ControlMove ControlSend ControlSetText ControlShow ControlTreeView Cos Dec DirCopy DirCreate DirGetSize DirMove DirRemove DllCall DllCallAddress DllCallbackFree DllCallbackGetPtr DllCallbackRegister DllClose DllOpen DllStructCreate DllStructGetData DllStructGetPtr DllStructGetSize DllStructSetData DriveGetDrive DriveGetFileSystem DriveGetLabel DriveGetSerial DriveGetType DriveMapAdd DriveMapDel DriveMapGet DriveSetLabel DriveSpaceFree DriveSpaceTotal DriveStatus EnvGet EnvSet EnvUpdate Eval Execute Exp FileChangeDir FileClose FileCopy FileCreateNTFSLink FileCreateShortcut FileDelete FileExists FileFindFirstFile FileFindNextFile FileFlush FileGetAttrib FileGetEncoding FileGetLongName FileGetPos FileGetShortcut FileGetShortName FileGetSize FileGetTime FileGetVersion FileInstall FileMove FileOpen FileOpenDialog FileRead FileReadLine FileReadToArray FileRecycle FileRecycleEmpty FileSaveDialog FileSelectFolder FileSetAttrib FileSetEnd FileSetPos FileSetTime FileWrite FileWriteLine Floor FtpSetProxy FuncName GUICreate GUICtrlCreateAvi GUICtrlCreateButton GUICtrlCreateCheckbox GUICtrlCreateCombo GUICtrlCreateContextMenu GUICtrlCreateDate GUICtrlCreateDummy GUICtrlCreateEdit GUICtrlCreateGraphic GUICtrlCreateGroup GUICtrlCreateIcon GUICtrlCreateInput GUICtrlCreateLabel GUICtrlCreateList GUICtrlCreateListView GUICtrlCreateListViewItem GUICtrlCreateMenu GUICtrlCreateMenuItem GUICtrlCreateMonthCal GUICtrlCreateObj GUICtrlCreatePic GUICtrlCreateProgress GUICtrlCreateRadio GUICtrlCreateSlider GUICtrlCreateTab GUICtrlCreateTabItem GUICtrlCreateTreeView GUICtrlCreateTreeViewItem GUICtrlCreateUpdown GUICtrlDelete GUICtrlGetHandle GUICtrlGetState GUICtrlRead GUICtrlRecvMsg GUICtrlRegisterListViewSort GUICtrlSendMsg GUICtrlSendToDummy GUICtrlSetBkColor GUICtrlSetColor GUICtrlSetCursor GUICtrlSetData GUICtrlSetDefBkColor GUICtrlSetDefColor GUICtrlSetFont GUICtrlSetGraphic GUICtrlSetImage GUICtrlSetLimit GUICtrlSetOnEvent GUICtrlSetPos GUICtrlSetResizing GUICtrlSetState GUICtrlSetStyle GUICtrlSetTip GUIDelete GUIGetCursorInfo GUIGetMsg GUIGetStyle GUIRegisterMsg GUISetAccelerators GUISetBkColor GUISetCoord GUISetCursor GUISetFont GUISetHelp GUISetIcon GUISetOnEvent GUISetState GUISetStyle GUIStartGroup GUISwitch Hex HotKeySet HttpSetProxy HttpSetUserAgent HWnd InetClose InetGet InetGetInfo InetGetSize InetRead IniDelete IniRead IniReadSection IniReadSectionNames IniRenameSection IniWrite IniWriteSection InputBox Int IsAdmin IsArray IsBinary IsBool IsDeclared IsDllStruct IsFloat IsFunc IsHWnd IsInt IsKeyword IsNumber IsObj IsPtr IsString Log MemGetStats Mod MouseClick MouseClickDrag MouseDown MouseGetCursor MouseGetPos MouseMove MouseUp MouseWheel MsgBox Number ObjCreate ObjCreateInterface ObjEvent ObjGet ObjName OnAutoItExitRegister OnAutoItExitUnRegister Ping PixelChecksum PixelGetColor PixelSearch ProcessClose ProcessExists ProcessGetStats ProcessList ProcessSetPriority ProcessWait ProcessWaitClose ProgressOff ProgressOn ProgressSet Ptr Random RegDelete RegEnumKey RegEnumVal RegRead RegWrite Round Run RunAs RunAsWait RunWait Send SendKeepActive SetError SetExtended ShellExecute ShellExecuteWait Shutdown Sin Sleep SoundPlay SoundSetWaveVolume SplashImageOn SplashOff SplashTextOn Sqrt SRandom StatusbarGetText StderrRead StdinWrite StdioClose StdoutRead String StringAddCR StringCompare StringFormat StringFromASCIIArray StringInStr StringIsAlNum StringIsAlpha StringIsASCII StringIsDigit StringIsFloat StringIsInt StringIsLower StringIsSpace StringIsUpper StringIsXDigit StringLeft StringLen StringLower StringMid StringRegExp StringRegExpReplace StringReplace StringReverse StringRight StringSplit StringStripCR StringStripWS StringToASCIIArray StringToBinary StringTrimLeft StringTrimRight StringUpper Tan TCPAccept TCPCloseSocket TCPConnect TCPListen TCPNameToIP TCPRecv TCPSend TCPShutdown, UDPShutdown TCPStartup, UDPStartup TimerDiff TimerInit ToolTip TrayCreateItem TrayCreateMenu TrayGetMsg TrayItemDelete TrayItemGetHandle TrayItemGetState TrayItemGetText TrayItemSetOnEvent TrayItemSetState TrayItemSetText TraySetClick TraySetIcon TraySetOnEvent TraySetPauseIcon TraySetState TraySetToolTip TrayTip UBound UDPBind UDPCloseSocket UDPOpen UDPRecv UDPSend VarGetType WinActivate WinActive WinClose WinExists WinFlash WinGetCaretPos WinGetClassList WinGetClientSize WinGetHandle WinGetPos WinGetProcess WinGetState WinGetText WinGetTitle WinKill WinList WinMenuSelectItem WinMinimizeAll WinMinimizeAllUndo WinMove WinSetOnTop WinSetState WinSetTitle WinSetTrans WinWait",
-literal:"True False And Null Not Or"},contains:[t,r,i,n,{className:"meta",
-begin:"#",end:"$",keywords:{
-"meta-keyword":"comments include include-once NoTrayIcon OnAutoItStartRegister pragma compile RequireAdmin"
+keyword:"ByRef Case Const ContinueCase ContinueLoop Dim Do Else ElseIf EndFunc EndIf EndSelect EndSwitch EndWith Enum Exit ExitLoop For Func Global If In Local Next ReDim Return Select Static Step Switch Then To Until Volatile WEnd While With",
+built_in:"Abs ACos AdlibRegister AdlibUnRegister Asc AscW ASin Assign ATan AutoItSetOption AutoItWinGetTitle AutoItWinSetTitle Beep Binary BinaryLen BinaryMid BinaryToString BitAND BitNOT BitOR BitRotate BitShift BitXOR BlockInput Break Call CDTray Ceiling Chr ChrW ClipGet ClipPut ConsoleRead ConsoleWrite ConsoleWriteError ControlClick ControlCommand ControlDisable ControlEnable ControlFocus ControlGetFocus ControlGetHandle ControlGetPos ControlGetText ControlHide ControlListView ControlMove ControlSend ControlSetText ControlShow ControlTreeView Cos Dec DirCopy DirCreate DirGetSize DirMove DirRemove DllCall DllCallAddress DllCallbackFree DllCallbackGetPtr DllCallbackRegister DllClose DllOpen DllStructCreate DllStructGetData DllStructGetPtr DllStructGetSize DllStructSetData DriveGetDrive DriveGetFileSystem DriveGetLabel DriveGetSerial DriveGetType DriveMapAdd DriveMapDel DriveMapGet DriveSetLabel DriveSpaceFree DriveSpaceTotal DriveStatus EnvGet EnvSet EnvUpdate Eval Execute Exp FileChangeDir FileClose FileCopy FileCreateNTFSLink FileCreateShortcut FileDelete FileExists FileFindFirstFile FileFindNextFile FileFlush FileGetAttrib FileGetEncoding FileGetLongName FileGetPos FileGetShortcut FileGetShortName FileGetSize FileGetTime FileGetVersion FileInstall FileMove FileOpen FileOpenDialog FileRead FileReadLine FileReadToArray FileRecycle FileRecycleEmpty FileSaveDialog FileSelectFolder FileSetAttrib FileSetEnd FileSetPos FileSetTime FileWrite FileWriteLine Floor FtpSetProxy FuncName GUICreate GUICtrlCreateAvi GUICtrlCreateButton GUICtrlCreateCheckbox GUICtrlCreateCombo GUICtrlCreateContextMenu GUICtrlCreateDate GUICtrlCreateDummy GUICtrlCreateEdit GUICtrlCreateGraphic GUICtrlCreateGroup GUICtrlCreateIcon GUICtrlCreateInput GUICtrlCreateLabel GUICtrlCreateList GUICtrlCreateListView GUICtrlCreateListViewItem GUICtrlCreateMenu GUICtrlCreateMenuItem GUICtrlCreateMonthCal GUICtrlCreateObj GUICtrlCreatePic GUICtrlCreateProgress GUICtrlCreateRadio GUICtrlCreateSlider GUICtrlCreateTab GUICtrlCreateTabItem GUICtrlCreateTreeView GUICtrlCreateTreeViewItem GUICtrlCreateUpdown GUICtrlDelete GUICtrlGetHandle GUICtrlGetState GUICtrlRead GUICtrlRecvMsg GUICtrlRegisterListViewSort GUICtrlSendMsg GUICtrlSendToDummy GUICtrlSetBkColor GUICtrlSetColor GUICtrlSetCursor GUICtrlSetData GUICtrlSetDefBkColor GUICtrlSetDefColor GUICtrlSetFont GUICtrlSetGraphic GUICtrlSetImage GUICtrlSetLimit GUICtrlSetOnEvent GUICtrlSetPos GUICtrlSetResizing GUICtrlSetState GUICtrlSetStyle GUICtrlSetTip GUIDelete GUIGetCursorInfo GUIGetMsg GUIGetStyle GUIRegisterMsg GUISetAccelerators GUISetBkColor GUISetCoord GUISetCursor GUISetFont GUISetHelp GUISetIcon GUISetOnEvent GUISetState GUISetStyle GUIStartGroup GUISwitch Hex HotKeySet HttpSetProxy HttpSetUserAgent HWnd InetClose InetGet InetGetInfo InetGetSize InetRead IniDelete IniRead IniReadSection IniReadSectionNames IniRenameSection IniWrite IniWriteSection InputBox Int IsAdmin IsArray IsBinary IsBool IsDeclared IsDllStruct IsFloat IsFunc IsHWnd IsInt IsKeyword IsNumber IsObj IsPtr IsString Log MemGetStats Mod MouseClick MouseClickDrag MouseDown MouseGetCursor MouseGetPos MouseMove MouseUp MouseWheel MsgBox Number ObjCreate ObjCreateInterface ObjEvent ObjGet ObjName OnAutoItExitRegister OnAutoItExitUnRegister Ping PixelChecksum PixelGetColor PixelSearch ProcessClose ProcessExists ProcessGetStats ProcessList ProcessSetPriority ProcessWait ProcessWaitClose ProgressOff ProgressOn ProgressSet Ptr Random RegDelete RegEnumKey RegEnumVal RegRead RegWrite Round Run RunAs RunAsWait RunWait Send SendKeepActive SetError SetExtended ShellExecute ShellExecuteWait Shutdown Sin Sleep SoundPlay SoundSetWaveVolume SplashImageOn SplashOff SplashTextOn Sqrt SRandom StatusbarGetText StderrRead StdinWrite StdioClose StdoutRead String StringAddCR StringCompare StringFormat StringFromASCIIArray StringInStr StringIsAlNum StringIsAlpha StringIsASCII StringIsDigit StringIsFloat StringIsInt StringIsLower StringIsSpace StringIsUpper StringIsXDigit StringLeft StringLen StringLower StringMid StringRegExp StringRegExpReplace StringReplace StringReverse StringRight StringSplit StringStripCR StringStripWS StringToASCIIArray StringToBinary StringTrimLeft StringTrimRight StringUpper Tan TCPAccept TCPCloseSocket TCPConnect TCPListen TCPNameToIP TCPRecv TCPSend TCPShutdown, UDPShutdown TCPStartup, UDPStartup TimerDiff TimerInit ToolTip TrayCreateItem TrayCreateMenu TrayGetMsg TrayItemDelete TrayItemGetHandle TrayItemGetState TrayItemGetText TrayItemSetOnEvent TrayItemSetState TrayItemSetText TraySetClick TraySetIcon TraySetOnEvent TraySetPauseIcon TraySetState TraySetToolTip TrayTip UBound UDPBind UDPCloseSocket UDPOpen UDPRecv UDPSend VarGetType WinActivate WinActive WinClose WinExists WinFlash WinGetCaretPos WinGetClassList WinGetClientSize WinGetHandle WinGetPos WinGetProcess WinGetState WinGetText WinGetTitle WinKill WinList WinMenuSelectItem WinMinimizeAll WinMinimizeAllUndo WinMove WinSetOnTop WinSetState WinSetTitle WinSetTrans WinWait WinWaitActive WinWaitClose WinWaitNotActive",
+literal:"True False And Null Not Or Default"},contains:[t,r,i,n,{
+className:"meta",begin:"#",end:"$",keywords:{
+"meta-keyword":["EndRegion","forcedef","forceref","ignorefunc","include","include-once","NoTrayIcon","OnAutoItStartRegister","pragma","Region","RequireAdmin","Tidy_Off","Tidy_On","Tidy_Parameters"]
},contains:[{begin:/\\\n/,relevance:0},{beginKeywords:"include",keywords:{
"meta-keyword":"include"},end:"$",contains:[i,{className:"meta-string",
variants:[{begin:"<",end:">"},{begin:/"/,end:/"/,contains:[{begin:/""/,
@@ -746,16 +753,16 @@
variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{
beginKeywords:"new throw return else",end:/;/}],keywords:u,contains:p.concat([{
begin:/\(/,end:/\)/,keywords:u,contains:p.concat(["self"]),relevance:0}]),
-relevance:0},_={className:"function",begin:"("+r+"[\\*&\\s]+)+"+d,
+relevance:0},g={className:"function",begin:"("+r+"[\\*&\\s]+)+"+d,
returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:u,illegal:/[^\w\s\*&:<>.]/,
contains:[{begin:"decltype\\(auto\\)",keywords:u,relevance:0},{begin:d,
-returnBegin:!0,contains:[l],relevance:0},{className:"params",begin:/\(/,
-end:/\)/,keywords:u,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,i,c,s,{
-begin:/\(/,end:/\)/,keywords:u,relevance:0,
-contains:["self",n,t.C_BLOCK_COMMENT_MODE,i,c,s]}]
-},s,n,t.C_BLOCK_COMMENT_MODE,o]};return{name:"C++",
+returnBegin:!0,contains:[l],relevance:0},{begin:/::/,relevance:0},{begin:/:/,
+endsWithParent:!0,contains:[i,c]},{className:"params",begin:/\(/,end:/\)/,
+keywords:u,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,i,c,s,{begin:/\(/,
+end:/\)/,keywords:u,relevance:0,contains:["self",n,t.C_BLOCK_COMMENT_MODE,i,c,s]
+}]},s,n,t.C_BLOCK_COMMENT_MODE,o]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"</",
-contains:[].concat(m,_,p,[o,{
+contains:[].concat(m,g,p,[o,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",
end:">",keywords:u,contains:["self",s]},{begin:t.IDENT_RE+"::",keywords:u},{
className:"class",beginKeywords:"enum class struct union",end:/[{;:<>=]/,
@@ -842,7 +849,7 @@
contains:[e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*","\\*/",{contains:["self"]}),{
className:"meta",begin:'@[a-z]\\w*(?::"[^"]*")?'}].concat(n)}}})());
hljs.registerLanguage("clean",(()=>{"use strict";return e=>({name:"Clean",
-aliases:["clean","icl","dcl"],keywords:{
+aliases:["icl","dcl"],keywords:{
keyword:"if let in with where case of class instance otherwise implementation definition system module from import qualified as special code inline foreign export ccall stdcall generic derive infix infixl infixr",
built_in:"Int Real Char Bool",literal:"True False"},
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,{
@@ -873,7 +880,7 @@
},contains:[{className:"variable",begin:/\$\{/,end:/\}/
},e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE]})})());
hljs.registerLanguage("coffeescript",(()=>{"use strict"
-;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
+;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
;return r=>{const t={
keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((i=["var","const","let","function","static"],
e=>!i.includes(e))),literal:n.concat(["yes","no","on","off"]),
@@ -906,7 +913,7 @@
className:"type",excludeBegin:!0,begin:"\\|\\s*",end:"\\w+"},{begin:/[-=]>/}]})
})());
hljs.registerLanguage("cos",(()=>{"use strict";return e=>({
-name:"Cach\xe9 Object Script",case_insensitive:!0,aliases:["cos","cls"],
+name:"Cach\xe9 Object Script",case_insensitive:!0,aliases:["cls"],
keywords:"property parameter class classmethod clientmethod extends as break catch close continue do d|0 else elseif for goto halt hang h|0 if job j|0 kill k|0 lock l|0 merge new open quit q|0 read r|0 return set s|0 tcommit throw trollback try tstart use view while write w|0 xecute x|0 zkill znspace zn ztrap zwrite zw zzdump zzwrite print zbreak zinsert zload zprint zremove zsave zzprint mv mvcall mvcrt mvdim mvprint zquit zsync ascii",
contains:[{className:"number",begin:"\\b(\\d+(\\.\\d*)?|\\.\\d+)",relevance:0},{
className:"string",variants:[{begin:'"',end:'"',contains:[{begin:'""',
@@ -948,11 +955,11 @@
relevance:0},_={className:"function",begin:"("+a+"[\\*&\\s]+)+"+d,
returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:u,illegal:/[^\w\s\*&:<>.]/,
contains:[{begin:"decltype\\(auto\\)",keywords:u,relevance:0},{begin:d,
-returnBegin:!0,contains:[l],relevance:0},{className:"params",begin:/\(/,
-end:/\)/,keywords:u,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,s,o,i,{
-begin:/\(/,end:/\)/,keywords:u,relevance:0,
-contains:["self",n,t.C_BLOCK_COMMENT_MODE,s,o,i]}]
-},i,n,t.C_BLOCK_COMMENT_MODE,c]};return{name:"C++",
+returnBegin:!0,contains:[l],relevance:0},{begin:/::/,relevance:0},{begin:/:/,
+endsWithParent:!0,contains:[s,o]},{className:"params",begin:/\(/,end:/\)/,
+keywords:u,relevance:0,contains:[n,t.C_BLOCK_COMMENT_MODE,s,o,i,{begin:/\(/,
+end:/\)/,keywords:u,relevance:0,contains:["self",n,t.C_BLOCK_COMMENT_MODE,s,o,i]
+}]},i,n,t.C_BLOCK_COMMENT_MODE,c]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"</",
contains:[].concat(p,_,m,[c,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",
@@ -1557,9 +1564,9 @@
contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,{
className:"meta",begin:"#",end:"$"}]})})());
hljs.registerLanguage("gml",(()=>{"use strict";return e=>({name:"GML",
-aliases:["gml","GML"],case_insensitive:!1,keywords:{
-keyword:"begin end if then else while do for break continue with until repeat exit and or xor not return mod div switch case default var globalvar enum #macro #region #endregion",
-built_in:"is_real is_string is_array is_undefined is_int32 is_int64 is_ptr is_vec3 is_vec4 is_matrix is_bool typeof variable_global_exists variable_global_get variable_global_set variable_instance_exists variable_instance_get variable_instance_set variable_instance_get_names array_length_1d array_length_2d array_height_2d array_equals array_create array_copy random random_range irandom irandom_range random_set_seed random_get_seed randomize randomise choose abs round floor ceil sign frac sqrt sqr exp ln log2 log10 sin cos tan arcsin arccos arctan arctan2 dsin dcos dtan darcsin darccos darctan darctan2 degtorad radtodeg power logn min max mean median clamp lerp dot_product dot_product_3d dot_product_normalised dot_product_3d_normalised dot_product_normalized dot_product_3d_normalized math_set_epsilon math_get_epsilon angle_difference point_distance_3d point_distance point_direction lengthdir_x lengthdir_y real string int64 ptr string_format chr ansi_char ord string_length string_byte_length string_pos string_copy string_char_at string_ord_at string_byte_at string_set_byte_at string_delete string_insert string_lower string_upper string_repeat string_letters string_digits string_lettersdigits string_replace string_replace_all string_count string_hash_to_newline clipboard_has_text clipboard_set_text clipboard_get_text date_current_datetime date_create_datetime date_valid_datetime date_inc_year date_inc_month date_inc_week date_inc_day date_inc_hour date_inc_minute date_inc_second date_get_year date_get_month date_get_week date_get_day date_get_hour date_get_minute date_get_second date_get_weekday date_get_day_of_year date_get_hour_of_year date_get_minute_of_year date_get_second_of_year date_year_span date_month_span date_week_span date_day_span date_hour_span date_minute_span date_second_span date_compare_datetime date_compare_date date_compare_time date_date_of date_time_of date_datetime_string date_date_string date_time_string date_days_in_month date_days_in_year date_leap_year date_is_today date_set_timezone date_get_timezone game_set_speed game_get_speed motion_set motion_add place_free place_empty place_meeting place_snapped move_random move_snap move_towards_point move_contact_solid move_contact_all move_outside_solid move_outside_all move_bounce_solid move_bounce_all move_wrap distance_to_point distance_to_object position_empty position_meeting path_start path_end mp_linear_step mp_potential_step mp_linear_step_object mp_potential_step_object mp_potential_settings mp_linear_path mp_potential_path mp_linear_path_object mp_potential_path_object mp_grid_create mp_grid_destroy mp_grid_clear_all mp_grid_clear_cell mp_grid_clear_rectangle mp_grid_add_cell mp_grid_get_cell mp_grid_add_rectangle mp_grid_add_instances mp_grid_path mp_grid_draw mp_grid_to_ds_grid collision_point collision_rectangle collision_circle collision_ellipse collision_line collision_point_list collision_rectangle_list collision_circle_list collision_ellipse_list collision_line_list instance_position_list instance_place_list point_in_rectangle point_in_triangle point_in_circle rectangle_in_rectangle rectangle_in_triangle rectangle_in_circle instance_find instance_exists instance_number instance_position instance_nearest instance_furthest instance_place instance_create_depth instance_create_layer instance_copy instance_change instance_destroy position_destroy position_change instance_id_get instance_deactivate_all instance_deactivate_object instance_deactivate_region instance_activate_all instance_activate_object instance_activate_region room_goto room_goto_previous room_goto_next room_previous room_next room_restart game_end game_restart game_load game_save game_save_buffer game_load_buffer event_perform event_user event_perform_object event_inherited show_debug_message show_debug_overlay debug_event debug_get_callstack alarm_get alarm_set font_texture_page_size keyboard_set_map keyboard_get_map keyboard_unset_map keyboard_check keyboard_check_pressed keyboard_check_released keyboard_check_direct keyboard_get_numlock keyboard_set_numlock keyboard_key_press keyboard_key_release keyboard_clear io_clear mouse_check_button mouse_check_button_pressed mouse_check_button_released mouse_wheel_up mouse_wheel_down mouse_clear draw_self draw_sprite draw_sprite_pos draw_sprite_ext draw_sprite_stretched draw_sprite_stretched_ext draw_sprite_tiled draw_sprite_tiled_ext draw_sprite_part draw_sprite_part_ext draw_sprite_general draw_clear draw_clear_alpha draw_point draw_line draw_line_width draw_rectangle draw_roundrect draw_roundrect_ext draw_triangle draw_circle draw_ellipse draw_set_circle_precision draw_arrow draw_button draw_path draw_healthbar draw_getpixel draw_getpixel_ext draw_set_colour draw_set_color draw_set_alpha draw_get_colour draw_get_color draw_get_alpha merge_colour make_colour_rgb make_colour_hsv colour_get_red colour_get_green colour_get_blue colour_get_hue colour_get_saturation colour_get_value merge_color make_color_rgb make_color_hsv color_get_red color_get_green color_get_blue color_get_hue color_get_saturation color_get_value merge_color screen_save screen_save_part draw_set_font draw_set_halign draw_set_valign draw_text draw_text_ext string_width string_height string_width_ext string_height_ext draw_text_transformed draw_text_ext_transformed draw_text_colour draw_text_ext_colour draw_text_transformed_colour draw_text_ext_transformed_colour draw_text_color draw_text_ext_color draw_text_transformed_color draw_text_ext_transformed_color draw_point_colour draw_line_colour draw_line_width_colour draw_rectangle_colour draw_roundrect_colour draw_roundrect_colour_ext draw_triangle_colour draw_circle_colour draw_ellipse_colour draw_point_color draw_line_color draw_line_width_color draw_rectangle_color draw_roundrect_color draw_roundrect_color_ext draw_triangle_color draw_circle_color draw_ellipse_color draw_primitive_begin draw_vertex draw_vertex_colour draw_vertex_color draw_primitive_end sprite_get_uvs font_get_uvs sprite_get_texture font_get_texture texture_get_width texture_get_height texture_get_uvs draw_primitive_begin_texture draw_vertex_texture draw_vertex_texture_colour draw_vertex_texture_color texture_global_scale surface_create surface_create_ext surface_resize surface_free surface_exists surface_get_width surface_get_height surface_get_texture surface_set_target surface_set_target_ext surface_reset_target surface_depth_disable surface_get_depth_disable draw_surface draw_surface_stretched draw_surface_tiled draw_surface_part draw_surface_ext draw_surface_stretched_ext draw_surface_tiled_ext draw_surface_part_ext draw_surface_general surface_getpixel surface_getpixel_ext surface_save surface_save_part surface_copy surface_copy_part application_surface_draw_enable application_get_position application_surface_enable application_surface_is_enabled display_get_width display_get_height display_get_orientation display_get_gui_width display_get_gui_height display_reset display_mouse_get_x display_mouse_get_y display_mouse_set display_set_ui_visibility window_set_fullscreen window_get_fullscreen window_set_caption window_set_min_width window_set_max_width window_set_min_height window_set_max_height window_get_visible_rects window_get_caption window_set_cursor window_get_cursor window_set_colour window_get_colour window_set_color window_get_color window_set_position window_set_size window_set_rectangle window_center window_get_x window_get_y window_get_width window_get_height window_mouse_get_x window_mouse_get_y window_mouse_set window_view_mouse_get_x window_view_mouse_get_y window_views_mouse_get_x window_views_mouse_get_y audio_listener_position audio_listener_velocity audio_listener_orientation audio_emitter_position audio_emitter_create audio_emitter_free audio_emitter_exists audio_emitter_pitch audio_emitter_velocity audio_emitter_falloff audio_emitter_gain audio_play_sound audio_play_sound_on audio_play_sound_at audio_stop_sound audio_resume_music audio_music_is_playing audio_resume_sound audio_pause_sound audio_pause_music audio_channel_num audio_sound_length audio_get_type audio_falloff_set_model audio_play_music audio_stop_music audio_master_gain audio_music_gain audio_sound_gain audio_sound_pitch audio_stop_all audio_resume_all audio_pause_all audio_is_playing audio_is_paused audio_exists audio_sound_set_track_position audio_sound_get_track_position audio_emitter_get_gain audio_emitter_get_pitch audio_emitter_get_x audio_emitter_get_y audio_emitter_get_z audio_emitter_get_vx audio_emitter_get_vy audio_emitter_get_vz audio_listener_set_position audio_listener_set_velocity audio_listener_set_orientation audio_listener_get_data audio_set_master_gain audio_get_master_gain audio_sound_get_gain audio_sound_get_pitch audio_get_name audio_sound_set_track_position audio_sound_get_track_position audio_create_stream audio_destroy_stream audio_create_sync_group audio_destroy_sync_group audio_play_in_sync_group audio_start_sync_group audio_stop_sync_group audio_pause_sync_group audio_resume_sync_group audio_sync_group_get_track_pos audio_sync_group_debug audio_sync_group_is_playing audio_debug audio_group_load audio_group_unload audio_group_is_loaded audio_group_load_progress audio_group_name audio_group_stop_all audio_group_set_gain audio_create_buffer_sound audio_free_buffer_sound audio_create_play_queue audio_free_play_queue audio_queue_sound audio_get_recorder_count audio_get_recorder_info audio_start_recording audio_stop_recording audio_sound_get_listener_mask audio_emitter_get_listener_mask audio_get_listener_mask audio_sound_set_listener_mask audio_emitter_set_listener_mask audio_set_listener_mask audio_get_listener_count audio_get_listener_info audio_system show_message show_message_async clickable_add clickable_add_ext clickable_change clickable_change_ext clickable_delete clickable_exists clickable_set_style show_question show_question_async get_integer get_string get_integer_async get_string_async get_login_async get_open_filename get_save_filename get_open_filename_ext get_save_filename_ext show_error highscore_clear highscore_add highscore_value highscore_name draw_highscore sprite_exists sprite_get_name sprite_get_number sprite_get_width sprite_get_height sprite_get_xoffset sprite_get_yoffset sprite_get_bbox_left sprite_get_bbox_right sprite_get_bbox_top sprite_get_bbox_bottom sprite_save sprite_save_strip sprite_set_cache_size sprite_set_cache_size_ext sprite_get_tpe sprite_prefetch sprite_prefetch_multi sprite_flush sprite_flush_multi sprite_set_speed sprite_get_speed_type sprite_get_speed font_exists font_get_name font_get_fontname font_get_bold font_get_italic font_get_first font_get_last font_get_size font_set_cache_size path_exists path_get_name path_get_length path_get_time path_get_kind path_get_closed path_get_precision path_get_number path_get_point_x path_get_point_y path_get_point_speed path_get_x path_get_y path_get_speed script_exists script_get_name timeline_add timeline_delete timeline_clear timeline_exists timeline_get_name timeline_moment_clear timeline_moment_add_script timeline_size timeline_max_moment object_exists object_get_name object_get_sprite object_get_solid object_get_visible object_get_persistent object_get_mask object_get_parent object_get_physics object_is_ancestor room_exists room_get_name sprite_set_offset sprite_duplicate sprite_assign sprite_merge sprite_add sprite_replace sprite_create_from_surface sprite_add_from_surface sprite_delete sprite_set_alpha_from_sprite sprite_collision_mask font_add_enable_aa font_add_get_enable_aa font_add font_add_sprite font_add_sprite_ext font_replace font_replace_sprite font_replace_sprite_ext font_delete path_set_kind path_set_closed path_set_precision path_add path_assign path_duplicate path_append path_delete path_add_point path_insert_point path_change_point path_delete_point path_clear_points path_reverse path_mirror path_flip path_rotate path_rescale path_shift script_execute object_set_sprite object_set_solid object_set_visible object_set_persistent object_set_mask room_set_width room_set_height room_set_persistent room_set_background_colour room_set_background_color room_set_view room_set_viewport room_get_viewport room_set_view_enabled room_add room_duplicate room_assign room_instance_add room_instance_clear room_get_camera room_set_camera asset_get_index asset_get_type file_text_open_from_string file_text_open_read file_text_open_write file_text_open_append file_text_close file_text_write_string file_text_write_real file_text_writeln file_text_read_string file_text_read_real file_text_readln file_text_eof file_text_eoln file_exists file_delete file_rename file_copy directory_exists directory_create directory_destroy file_find_first file_find_next file_find_close file_attributes filename_name filename_path filename_dir filename_drive filename_ext filename_change_ext file_bin_open file_bin_rewrite file_bin_close file_bin_position file_bin_size file_bin_seek file_bin_write_byte file_bin_read_byte parameter_count parameter_string environment_get_variable ini_open_from_string ini_open ini_close ini_read_string ini_read_real ini_write_string ini_write_real ini_key_exists ini_section_exists ini_key_delete ini_section_delete ds_set_precision ds_exists ds_stack_create ds_stack_destroy ds_stack_clear ds_stack_copy ds_stack_size ds_stack_empty ds_stack_push ds_stack_pop ds_stack_top ds_stack_write ds_stack_read ds_queue_create ds_queue_destroy ds_queue_clear ds_queue_copy ds_queue_size ds_queue_empty ds_queue_enqueue ds_queue_dequeue ds_queue_head ds_queue_tail ds_queue_write ds_queue_read ds_list_create ds_list_destroy ds_list_clear ds_list_copy ds_list_size ds_list_empty ds_list_add ds_list_insert ds_list_replace ds_list_delete ds_list_find_index ds_list_find_value ds_list_mark_as_list ds_list_mark_as_map ds_list_sort ds_list_shuffle ds_list_write ds_list_read ds_list_set ds_map_create ds_map_destroy ds_map_clear ds_map_copy ds_map_size ds_map_empty ds_map_add ds_map_add_list ds_map_add_map ds_map_replace ds_map_replace_map ds_map_replace_list ds_map_delete ds_map_exists ds_map_find_value ds_map_find_previous ds_map_find_next ds_map_find_first ds_map_find_last ds_map_write ds_map_read ds_map_secure_save ds_map_secure_load ds_map_secure_load_buffer ds_map_secure_save_buffer ds_map_set ds_priority_create ds_priority_destroy ds_priority_clear ds_priority_copy ds_priority_size ds_priority_empty ds_priority_add ds_priority_change_priority ds_priority_find_priority ds_priority_delete_value ds_priority_delete_min ds_priority_find_min ds_priority_delete_max ds_priority_find_max ds_priority_write ds_priority_read ds_grid_create ds_grid_destroy ds_grid_copy ds_grid_resize ds_grid_width ds_grid_height ds_grid_clear ds_grid_set ds_grid_add ds_grid_multiply ds_grid_set_region ds_grid_add_region ds_grid_multiply_region ds_grid_set_disk ds_grid_add_disk ds_grid_multiply_disk ds_grid_set_grid_region ds_grid_add_grid_region ds_grid_multiply_grid_region ds_grid_get ds_grid_get_sum ds_grid_get_max ds_grid_get_min ds_grid_get_mean ds_grid_get_disk_sum ds_grid_get_disk_min ds_grid_get_disk_max ds_grid_get_disk_mean ds_grid_value_exists ds_grid_value_x ds_grid_value_y ds_grid_value_disk_exists ds_grid_value_disk_x ds_grid_value_disk_y ds_grid_shuffle ds_grid_write ds_grid_read ds_grid_sort ds_grid_set ds_grid_get effect_create_below effect_create_above effect_clear part_type_create part_type_destroy part_type_exists part_type_clear part_type_shape part_type_sprite part_type_size part_type_scale part_type_orientation part_type_life part_type_step part_type_death part_type_speed part_type_direction part_type_gravity part_type_colour1 part_type_colour2 part_type_colour3 part_type_colour_mix part_type_colour_rgb part_type_colour_hsv part_type_color1 part_type_color2 part_type_color3 part_type_color_mix part_type_color_rgb part_type_color_hsv part_type_alpha1 part_type_alpha2 part_type_alpha3 part_type_blend part_system_create part_system_create_layer part_system_destroy part_system_exists part_system_clear part_system_draw_order part_system_depth part_system_position part_system_automatic_update part_system_automatic_draw part_system_update part_system_drawit part_system_get_layer part_system_layer part_particles_create part_particles_create_colour part_particles_create_color part_particles_clear part_particles_count part_emitter_create part_emitter_destroy part_emitter_destroy_all part_emitter_exists part_emitter_clear part_emitter_region part_emitter_burst part_emitter_stream external_call external_define external_free window_handle window_device matrix_get matrix_set matrix_build_identity matrix_build matrix_build_lookat matrix_build_projection_ortho matrix_build_projection_perspective matrix_build_projection_perspective_fov matrix_multiply matrix_transform_vertex matrix_stack_push matrix_stack_pop matrix_stack_multiply matrix_stack_set matrix_stack_clear matrix_stack_top matrix_stack_is_empty browser_input_capture os_get_config os_get_info os_get_language os_get_region os_lock_orientation display_get_dpi_x display_get_dpi_y display_set_gui_size display_set_gui_maximise display_set_gui_maximize device_mouse_dbclick_enable display_set_timing_method display_get_timing_method display_set_sleep_margin display_get_sleep_margin virtual_key_add virtual_key_hide virtual_key_delete virtual_key_show draw_enable_drawevent draw_enable_swf_aa draw_set_swf_aa_level draw_get_swf_aa_level draw_texture_flush draw_flush gpu_set_blendenable gpu_set_ztestenable gpu_set_zfunc gpu_set_zwriteenable gpu_set_lightingenable gpu_set_fog gpu_set_cullmode gpu_set_blendmode gpu_set_blendmode_ext gpu_set_blendmode_ext_sepalpha gpu_set_colorwriteenable gpu_set_colourwriteenable gpu_set_alphatestenable gpu_set_alphatestref gpu_set_alphatestfunc gpu_set_texfilter gpu_set_texfilter_ext gpu_set_texrepeat gpu_set_texrepeat_ext gpu_set_tex_filter gpu_set_tex_filter_ext gpu_set_tex_repeat gpu_set_tex_repeat_ext gpu_set_tex_mip_filter gpu_set_tex_mip_filter_ext gpu_set_tex_mip_bias gpu_set_tex_mip_bias_ext gpu_set_tex_min_mip gpu_set_tex_min_mip_ext gpu_set_tex_max_mip gpu_set_tex_max_mip_ext gpu_set_tex_max_aniso gpu_set_tex_max_aniso_ext gpu_set_tex_mip_enable gpu_set_tex_mip_enable_ext gpu_get_blendenable gpu_get_ztestenable gpu_get_zfunc gpu_get_zwriteenable gpu_get_lightingenable gpu_get_fog gpu_get_cullmode gpu_get_blendmode gpu_get_blendmode_ext gpu_get_blendmode_ext_sepalpha gpu_get_blendmode_src gpu_get_blendmode_dest gpu_get_blendmode_srcalpha gpu_get_blendmode_destalpha gpu_get_colorwriteenable gpu_get_colourwriteenable gpu_get_alphatestenable gpu_get_alphatestref gpu_get_alphatestfunc gpu_get_texfilter gpu_get_texfilter_ext gpu_get_texrepeat gpu_get_texrepeat_ext gpu_get_tex_filter gpu_get_tex_filter_ext gpu_get_tex_repeat gpu_get_tex_repeat_ext gpu_get_tex_mip_filter gpu_get_tex_mip_filter_ext gpu_get_tex_mip_bias gpu_get_tex_mip_bias_ext gpu_get_tex_min_mip gpu_get_tex_min_mip_ext gpu_get_tex_max_mip gpu_get_tex_max_mip_ext gpu_get_tex_max_aniso gpu_get_tex_max_aniso_ext gpu_get_tex_mip_enable gpu_get_tex_mip_enable_ext gpu_push_state gpu_pop_state gpu_get_state gpu_set_state draw_light_define_ambient draw_light_define_direction draw_light_define_point draw_light_enable draw_set_lighting draw_light_get_ambient draw_light_get draw_get_lighting shop_leave_rating url_get_domain url_open url_open_ext url_open_full get_timer achievement_login achievement_logout achievement_post achievement_increment achievement_post_score achievement_available achievement_show_achievements achievement_show_leaderboards achievement_load_friends achievement_load_leaderboard achievement_send_challenge achievement_load_progress achievement_reset achievement_login_status achievement_get_pic achievement_show_challenge_notifications achievement_get_challenges achievement_event achievement_show achievement_get_info cloud_file_save cloud_string_save cloud_synchronise ads_enable ads_disable ads_setup ads_engagement_launch ads_engagement_available ads_engagement_active ads_event ads_event_preload ads_set_reward_callback ads_get_display_height ads_get_display_width ads_move ads_interstitial_available ads_interstitial_display device_get_tilt_x device_get_tilt_y device_get_tilt_z device_is_keypad_open device_mouse_check_button device_mouse_check_button_pressed device_mouse_check_button_released device_mouse_x device_mouse_y device_mouse_raw_x device_mouse_raw_y device_mouse_x_to_gui device_mouse_y_to_gui iap_activate iap_status iap_enumerate_products iap_restore_all iap_acquire iap_consume iap_product_details iap_purchase_details facebook_init facebook_login facebook_status facebook_graph_request facebook_dialog facebook_logout facebook_launch_offerwall facebook_post_message facebook_send_invite facebook_user_id facebook_accesstoken facebook_check_permission facebook_request_read_permissions facebook_request_publish_permissions gamepad_is_supported gamepad_get_device_count gamepad_is_connected gamepad_get_description gamepad_get_button_threshold gamepad_set_button_threshold gamepad_get_axis_deadzone gamepad_set_axis_deadzone gamepad_button_count gamepad_button_check gamepad_button_check_pressed gamepad_button_check_released gamepad_button_value gamepad_axis_count gamepad_axis_value gamepad_set_vibration gamepad_set_colour gamepad_set_color os_is_paused window_has_focus code_is_compiled http_get http_get_file http_post_string http_request json_encode json_decode zip_unzip load_csv base64_encode base64_decode md5_string_unicode md5_string_utf8 md5_file os_is_network_connected sha1_string_unicode sha1_string_utf8 sha1_file os_powersave_enable analytics_event analytics_event_ext win8_livetile_tile_notification win8_livetile_tile_clear win8_livetile_badge_notification win8_livetile_badge_clear win8_livetile_queue_enable win8_secondarytile_pin win8_secondarytile_badge_notification win8_secondarytile_delete win8_livetile_notification_begin win8_livetile_notification_secondary_begin win8_livetile_notification_expiry win8_livetile_notification_tag win8_livetile_notification_text_add win8_livetile_notification_image_add win8_livetile_notification_end win8_appbar_enable win8_appbar_add_element win8_appbar_remove_element win8_settingscharm_add_entry win8_settingscharm_add_html_entry win8_settingscharm_add_xaml_entry win8_settingscharm_set_xaml_property win8_settingscharm_get_xaml_property win8_settingscharm_remove_entry win8_share_image win8_share_screenshot win8_share_file win8_share_url win8_share_text win8_search_enable win8_search_disable win8_search_add_suggestions win8_device_touchscreen_available win8_license_initialize_sandbox win8_license_trial_version winphone_license_trial_version winphone_tile_title winphone_tile_count winphone_tile_back_title winphone_tile_back_content winphone_tile_back_content_wide winphone_tile_front_image winphone_tile_front_image_small winphone_tile_front_image_wide winphone_tile_back_image winphone_tile_back_image_wide winphone_tile_background_colour winphone_tile_background_color winphone_tile_icon_image winphone_tile_small_icon_image winphone_tile_wide_content winphone_tile_cycle_images winphone_tile_small_background_image physics_world_create physics_world_gravity physics_world_update_speed physics_world_update_iterations physics_world_draw_debug physics_pause_enable physics_fixture_create physics_fixture_set_kinematic physics_fixture_set_density physics_fixture_set_awake physics_fixture_set_restitution physics_fixture_set_friction physics_fixture_set_collision_group physics_fixture_set_sensor physics_fixture_set_linear_damping physics_fixture_set_angular_damping physics_fixture_set_circle_shape physics_fixture_set_box_shape physics_fixture_set_edge_shape physics_fixture_set_polygon_shape physics_fixture_set_chain_shape physics_fixture_add_point physics_fixture_bind physics_fixture_bind_ext physics_fixture_delete physics_apply_force physics_apply_impulse physics_apply_angular_impulse physics_apply_local_force physics_apply_local_impulse physics_apply_torque physics_mass_properties physics_draw_debug physics_test_overlap physics_remove_fixture physics_set_friction physics_set_density physics_set_restitution physics_get_friction physics_get_density physics_get_restitution physics_joint_distance_create physics_joint_rope_create physics_joint_revolute_create physics_joint_prismatic_create physics_joint_pulley_create physics_joint_wheel_create physics_joint_weld_create physics_joint_friction_create physics_joint_gear_create physics_joint_enable_motor physics_joint_get_value physics_joint_set_value physics_joint_delete physics_particle_create physics_particle_delete physics_particle_delete_region_circle physics_particle_delete_region_box physics_particle_delete_region_poly physics_particle_set_flags physics_particle_set_category_flags physics_particle_draw physics_particle_draw_ext physics_particle_count physics_particle_get_data physics_particle_get_data_particle physics_particle_group_begin physics_particle_group_circle physics_particle_group_box physics_particle_group_polygon physics_particle_group_add_point physics_particle_group_end physics_particle_group_join physics_particle_group_delete physics_particle_group_count physics_particle_group_get_data physics_particle_group_get_mass physics_particle_group_get_inertia physics_particle_group_get_centre_x physics_particle_group_get_centre_y physics_particle_group_get_vel_x physics_particle_group_get_vel_y physics_particle_group_get_ang_vel physics_particle_group_get_x physics_particle_group_get_y physics_particle_group_get_angle physics_particle_set_group_flags physics_particle_get_group_flags physics_particle_get_max_count physics_particle_get_radius physics_particle_get_density physics_particle_get_damping physics_particle_get_gravity_scale physics_particle_set_max_count physics_particle_set_radius physics_particle_set_density physics_particle_set_damping physics_particle_set_gravity_scale network_create_socket network_create_socket_ext network_create_server network_create_server_raw network_connect network_connect_raw network_send_packet network_send_raw network_send_broadcast network_send_udp network_send_udp_raw network_set_timeout network_set_config network_resolve network_destroy buffer_create buffer_write buffer_read buffer_seek buffer_get_surface buffer_set_surface buffer_delete buffer_exists buffer_get_type buffer_get_alignment buffer_poke buffer_peek buffer_save buffer_save_ext buffer_load buffer_load_ext buffer_load_partial buffer_copy buffer_fill buffer_get_size buffer_tell buffer_resize buffer_md5 buffer_sha1 buffer_base64_encode buffer_base64_decode buffer_base64_decode_ext buffer_sizeof buffer_get_address buffer_create_from_vertex_buffer buffer_create_from_vertex_buffer_ext buffer_copy_from_vertex_buffer buffer_async_group_begin buffer_async_group_option buffer_async_group_end buffer_load_async buffer_save_async gml_release_mode gml_pragma steam_activate_overlay steam_is_overlay_enabled steam_is_overlay_activated steam_get_persona_name steam_initialised steam_is_cloud_enabled_for_app steam_is_cloud_enabled_for_account steam_file_persisted steam_get_quota_total steam_get_quota_free steam_file_write steam_file_write_file steam_file_read steam_file_delete steam_file_exists steam_file_size steam_file_share steam_is_screenshot_requested steam_send_screenshot steam_is_user_logged_on steam_get_user_steam_id steam_user_owns_dlc steam_user_installed_dlc steam_set_achievement steam_get_achievement steam_clear_achievement steam_set_stat_int steam_set_stat_float steam_set_stat_avg_rate steam_get_stat_int steam_get_stat_float steam_get_stat_avg_rate steam_reset_all_stats steam_reset_all_stats_achievements steam_stats_ready steam_create_leaderboard steam_upload_score steam_upload_score_ext steam_download_scores_around_user steam_download_scores steam_download_friends_scores steam_upload_score_buffer steam_upload_score_buffer_ext steam_current_game_language steam_available_languages steam_activate_overlay_browser steam_activate_overlay_user steam_activate_overlay_store steam_get_user_persona_name steam_get_app_id steam_get_user_account_id steam_ugc_download steam_ugc_create_item steam_ugc_start_item_update steam_ugc_set_item_title steam_ugc_set_item_description steam_ugc_set_item_visibility steam_ugc_set_item_tags steam_ugc_set_item_content steam_ugc_set_item_preview steam_ugc_submit_item_update steam_ugc_get_item_update_progress steam_ugc_subscribe_item steam_ugc_unsubscribe_item steam_ugc_num_subscribed_items steam_ugc_get_subscribed_items steam_ugc_get_item_install_info steam_ugc_get_item_update_info steam_ugc_request_item_details steam_ugc_create_query_user steam_ugc_create_query_user_ex steam_ugc_create_query_all steam_ugc_create_query_all_ex steam_ugc_query_set_cloud_filename_filter steam_ugc_query_set_match_any_tag steam_ugc_query_set_search_text steam_ugc_query_set_ranked_by_trend_days steam_ugc_query_add_required_tag steam_ugc_query_add_excluded_tag steam_ugc_query_set_return_long_description steam_ugc_query_set_return_total_only steam_ugc_query_set_allow_cached_response steam_ugc_send_query shader_set shader_get_name shader_reset shader_current shader_is_compiled shader_get_sampler_index shader_get_uniform shader_set_uniform_i shader_set_uniform_i_array shader_set_uniform_f shader_set_uniform_f_array shader_set_uniform_matrix shader_set_uniform_matrix_array shader_enable_corner_id texture_set_stage texture_get_texel_width texture_get_texel_height shaders_are_supported vertex_format_begin vertex_format_end vertex_format_delete vertex_format_add_position vertex_format_add_position_3d vertex_format_add_colour vertex_format_add_color vertex_format_add_normal vertex_format_add_texcoord vertex_format_add_textcoord vertex_format_add_custom vertex_create_buffer vertex_create_buffer_ext vertex_delete_buffer vertex_begin vertex_end vertex_position vertex_position_3d vertex_colour vertex_color vertex_argb vertex_texcoord vertex_normal vertex_float1 vertex_float2 vertex_float3 vertex_float4 vertex_ubyte4 vertex_submit vertex_freeze vertex_get_number vertex_get_buffer_size vertex_create_buffer_from_buffer vertex_create_buffer_from_buffer_ext push_local_notification push_get_first_local_notification push_get_next_local_notification push_cancel_local_notification skeleton_animation_set skeleton_animation_get skeleton_animation_mix skeleton_animation_set_ext skeleton_animation_get_ext skeleton_animation_get_duration skeleton_animation_get_frames skeleton_animation_clear skeleton_skin_set skeleton_skin_get skeleton_attachment_set skeleton_attachment_get skeleton_attachment_create skeleton_collision_draw_set skeleton_bone_data_get skeleton_bone_data_set skeleton_bone_state_get skeleton_bone_state_set skeleton_get_minmax skeleton_get_num_bounds skeleton_get_bounds skeleton_animation_get_frame skeleton_animation_set_frame draw_skeleton draw_skeleton_time draw_skeleton_instance draw_skeleton_collision skeleton_animation_list skeleton_skin_list skeleton_slot_data layer_get_id layer_get_id_at_depth layer_get_depth layer_create layer_destroy layer_destroy_instances layer_add_instance layer_has_instance layer_set_visible layer_get_visible layer_exists layer_x layer_y layer_get_x layer_get_y layer_hspeed layer_vspeed layer_get_hspeed layer_get_vspeed layer_script_begin layer_script_end layer_shader layer_get_script_begin layer_get_script_end layer_get_shader layer_set_target_room layer_get_target_room layer_reset_target_room layer_get_all layer_get_all_elements layer_get_name layer_depth layer_get_element_layer layer_get_element_type layer_element_move layer_force_draw_depth layer_is_draw_depth_forced layer_get_forced_depth layer_background_get_id layer_background_exists layer_background_create layer_background_destroy layer_background_visible layer_background_change layer_background_sprite layer_background_htiled layer_background_vtiled layer_background_stretch layer_background_yscale layer_background_xscale layer_background_blend layer_background_alpha layer_background_index layer_background_speed layer_background_get_visible layer_background_get_sprite layer_background_get_htiled layer_background_get_vtiled layer_background_get_stretch layer_background_get_yscale layer_background_get_xscale layer_background_get_blend layer_background_get_alpha layer_background_get_index layer_background_get_speed layer_sprite_get_id layer_sprite_exists layer_sprite_create layer_sprite_destroy layer_sprite_change layer_sprite_index layer_sprite_speed layer_sprite_xscale layer_sprite_yscale layer_sprite_angle layer_sprite_blend layer_sprite_alpha layer_sprite_x layer_sprite_y layer_sprite_get_sprite layer_sprite_get_index layer_sprite_get_speed layer_sprite_get_xscale layer_sprite_get_yscale layer_sprite_get_angle layer_sprite_get_blend layer_sprite_get_alpha layer_sprite_get_x layer_sprite_get_y layer_tilemap_get_id layer_tilemap_exists layer_tilemap_create layer_tilemap_destroy tilemap_tileset tilemap_x tilemap_y tilemap_set tilemap_set_at_pixel tilemap_get_tileset tilemap_get_tile_width tilemap_get_tile_height tilemap_get_width tilemap_get_height tilemap_get_x tilemap_get_y tilemap_get tilemap_get_at_pixel tilemap_get_cell_x_at_pixel tilemap_get_cell_y_at_pixel tilemap_clear draw_tilemap draw_tile tilemap_set_global_mask tilemap_get_global_mask tilemap_set_mask tilemap_get_mask tilemap_get_frame tile_set_empty tile_set_index tile_set_flip tile_set_mirror tile_set_rotate tile_get_empty tile_get_index tile_get_flip tile_get_mirror tile_get_rotate layer_tile_exists layer_tile_create layer_tile_destroy layer_tile_change layer_tile_xscale layer_tile_yscale layer_tile_blend layer_tile_alpha layer_tile_x layer_tile_y layer_tile_region layer_tile_visible layer_tile_get_sprite layer_tile_get_xscale layer_tile_get_yscale layer_tile_get_blend layer_tile_get_alpha layer_tile_get_x layer_tile_get_y layer_tile_get_region layer_tile_get_visible layer_instance_get_instance instance_activate_layer instance_deactivate_layer camera_create camera_create_view camera_destroy camera_apply camera_get_active camera_get_default camera_set_default camera_set_view_mat camera_set_proj_mat camera_set_update_script camera_set_begin_script camera_set_end_script camera_set_view_pos camera_set_view_size camera_set_view_speed camera_set_view_border camera_set_view_angle camera_set_view_target camera_get_view_mat camera_get_proj_mat camera_get_update_script camera_get_begin_script camera_get_end_script camera_get_view_x camera_get_view_y camera_get_view_width camera_get_view_height camera_get_view_speed_x camera_get_view_speed_y camera_get_view_border_x camera_get_view_border_y camera_get_view_angle camera_get_view_target view_get_camera view_get_visible view_get_xport view_get_yport view_get_wport view_get_hport view_get_surface_id view_set_camera view_set_visible view_set_xport view_set_yport view_set_wport view_set_hport view_set_surface_id gesture_drag_time gesture_drag_distance gesture_flick_speed gesture_double_tap_time gesture_double_tap_distance gesture_pinch_distance gesture_pinch_angle_towards gesture_pinch_angle_away gesture_rotate_time gesture_rotate_angle gesture_tap_count gesture_get_drag_time gesture_get_drag_distance gesture_get_flick_speed gesture_get_double_tap_time gesture_get_double_tap_distance gesture_get_pinch_distance gesture_get_pinch_angle_towards gesture_get_pinch_angle_away gesture_get_rotate_time gesture_get_rotate_angle gesture_get_tap_count keyboard_virtual_show keyboard_virtual_hide keyboard_virtual_status keyboard_virtual_height",
+aliases:["GML"],case_insensitive:!1,keywords:{
+keyword:"begin end if then else while do for break continue with until repeat exit and or xor not return mod div switch case default var globalvar enum function constructor delete #macro #region #endregion",
+built_in:"is_real is_string is_array is_undefined is_int32 is_int64 is_ptr is_vec3 is_vec4 is_matrix is_bool is_method is_struct is_infinity is_nan is_numeric typeof variable_global_exists variable_global_get variable_global_set variable_instance_exists variable_instance_get variable_instance_set variable_instance_get_names variable_struct_exists variable_struct_get variable_struct_get_names variable_struct_names_count variable_struct_remove variable_struct_set array_delete array_insert array_length array_length_1d array_length_2d array_height_2d array_equals array_create array_copy array_pop array_push array_resize array_sort random random_range irandom irandom_range random_set_seed random_get_seed randomize randomise choose abs round floor ceil sign frac sqrt sqr exp ln log2 log10 sin cos tan arcsin arccos arctan arctan2 dsin dcos dtan darcsin darccos darctan darctan2 degtorad radtodeg power logn min max mean median clamp lerp dot_product dot_product_3d dot_product_normalised dot_product_3d_normalised dot_product_normalized dot_product_3d_normalized math_set_epsilon math_get_epsilon angle_difference point_distance_3d point_distance point_direction lengthdir_x lengthdir_y real string int64 ptr string_format chr ansi_char ord string_length string_byte_length string_pos string_copy string_char_at string_ord_at string_byte_at string_set_byte_at string_delete string_insert string_lower string_upper string_repeat string_letters string_digits string_lettersdigits string_replace string_replace_all string_count string_hash_to_newline clipboard_has_text clipboard_set_text clipboard_get_text date_current_datetime date_create_datetime date_valid_datetime date_inc_year date_inc_month date_inc_week date_inc_day date_inc_hour date_inc_minute date_inc_second date_get_year date_get_month date_get_week date_get_day date_get_hour date_get_minute date_get_second date_get_weekday date_get_day_of_year date_get_hour_of_year date_get_minute_of_year date_get_second_of_year date_year_span date_month_span date_week_span date_day_span date_hour_span date_minute_span date_second_span date_compare_datetime date_compare_date date_compare_time date_date_of date_time_of date_datetime_string date_date_string date_time_string date_days_in_month date_days_in_year date_leap_year date_is_today date_set_timezone date_get_timezone game_set_speed game_get_speed motion_set motion_add place_free place_empty place_meeting place_snapped move_random move_snap move_towards_point move_contact_solid move_contact_all move_outside_solid move_outside_all move_bounce_solid move_bounce_all move_wrap distance_to_point distance_to_object position_empty position_meeting path_start path_end mp_linear_step mp_potential_step mp_linear_step_object mp_potential_step_object mp_potential_settings mp_linear_path mp_potential_path mp_linear_path_object mp_potential_path_object mp_grid_create mp_grid_destroy mp_grid_clear_all mp_grid_clear_cell mp_grid_clear_rectangle mp_grid_add_cell mp_grid_get_cell mp_grid_add_rectangle mp_grid_add_instances mp_grid_path mp_grid_draw mp_grid_to_ds_grid collision_point collision_rectangle collision_circle collision_ellipse collision_line collision_point_list collision_rectangle_list collision_circle_list collision_ellipse_list collision_line_list instance_position_list instance_place_list point_in_rectangle point_in_triangle point_in_circle rectangle_in_rectangle rectangle_in_triangle rectangle_in_circle instance_find instance_exists instance_number instance_position instance_nearest instance_furthest instance_place instance_create_depth instance_create_layer instance_copy instance_change instance_destroy position_destroy position_change instance_id_get instance_deactivate_all instance_deactivate_object instance_deactivate_region instance_activate_all instance_activate_object instance_activate_region room_goto room_goto_previous room_goto_next room_previous room_next room_restart game_end game_restart game_load game_save game_save_buffer game_load_buffer event_perform event_user event_perform_object event_inherited show_debug_message show_debug_overlay debug_event debug_get_callstack alarm_get alarm_set font_texture_page_size keyboard_set_map keyboard_get_map keyboard_unset_map keyboard_check keyboard_check_pressed keyboard_check_released keyboard_check_direct keyboard_get_numlock keyboard_set_numlock keyboard_key_press keyboard_key_release keyboard_clear io_clear mouse_check_button mouse_check_button_pressed mouse_check_button_released mouse_wheel_up mouse_wheel_down mouse_clear draw_self draw_sprite draw_sprite_pos draw_sprite_ext draw_sprite_stretched draw_sprite_stretched_ext draw_sprite_tiled draw_sprite_tiled_ext draw_sprite_part draw_sprite_part_ext draw_sprite_general draw_clear draw_clear_alpha draw_point draw_line draw_line_width draw_rectangle draw_roundrect draw_roundrect_ext draw_triangle draw_circle draw_ellipse draw_set_circle_precision draw_arrow draw_button draw_path draw_healthbar draw_getpixel draw_getpixel_ext draw_set_colour draw_set_color draw_set_alpha draw_get_colour draw_get_color draw_get_alpha merge_colour make_colour_rgb make_colour_hsv colour_get_red colour_get_green colour_get_blue colour_get_hue colour_get_saturation colour_get_value merge_color make_color_rgb make_color_hsv color_get_red color_get_green color_get_blue color_get_hue color_get_saturation color_get_value merge_color screen_save screen_save_part draw_set_font draw_set_halign draw_set_valign draw_text draw_text_ext string_width string_height string_width_ext string_height_ext draw_text_transformed draw_text_ext_transformed draw_text_colour draw_text_ext_colour draw_text_transformed_colour draw_text_ext_transformed_colour draw_text_color draw_text_ext_color draw_text_transformed_color draw_text_ext_transformed_color draw_point_colour draw_line_colour draw_line_width_colour draw_rectangle_colour draw_roundrect_colour draw_roundrect_colour_ext draw_triangle_colour draw_circle_colour draw_ellipse_colour draw_point_color draw_line_color draw_line_width_color draw_rectangle_color draw_roundrect_color draw_roundrect_color_ext draw_triangle_color draw_circle_color draw_ellipse_color draw_primitive_begin draw_vertex draw_vertex_colour draw_vertex_color draw_primitive_end sprite_get_uvs font_get_uvs sprite_get_texture font_get_texture texture_get_width texture_get_height texture_get_uvs draw_primitive_begin_texture draw_vertex_texture draw_vertex_texture_colour draw_vertex_texture_color texture_global_scale surface_create surface_create_ext surface_resize surface_free surface_exists surface_get_width surface_get_height surface_get_texture surface_set_target surface_set_target_ext surface_reset_target surface_depth_disable surface_get_depth_disable draw_surface draw_surface_stretched draw_surface_tiled draw_surface_part draw_surface_ext draw_surface_stretched_ext draw_surface_tiled_ext draw_surface_part_ext draw_surface_general surface_getpixel surface_getpixel_ext surface_save surface_save_part surface_copy surface_copy_part application_surface_draw_enable application_get_position application_surface_enable application_surface_is_enabled display_get_width display_get_height display_get_orientation display_get_gui_width display_get_gui_height display_reset display_mouse_get_x display_mouse_get_y display_mouse_set display_set_ui_visibility window_set_fullscreen window_get_fullscreen window_set_caption window_set_min_width window_set_max_width window_set_min_height window_set_max_height window_get_visible_rects window_get_caption window_set_cursor window_get_cursor window_set_colour window_get_colour window_set_color window_get_color window_set_position window_set_size window_set_rectangle window_center window_get_x window_get_y window_get_width window_get_height window_mouse_get_x window_mouse_get_y window_mouse_set window_view_mouse_get_x window_view_mouse_get_y window_views_mouse_get_x window_views_mouse_get_y audio_listener_position audio_listener_velocity audio_listener_orientation audio_emitter_position audio_emitter_create audio_emitter_free audio_emitter_exists audio_emitter_pitch audio_emitter_velocity audio_emitter_falloff audio_emitter_gain audio_play_sound audio_play_sound_on audio_play_sound_at audio_stop_sound audio_resume_music audio_music_is_playing audio_resume_sound audio_pause_sound audio_pause_music audio_channel_num audio_sound_length audio_get_type audio_falloff_set_model audio_play_music audio_stop_music audio_master_gain audio_music_gain audio_sound_gain audio_sound_pitch audio_stop_all audio_resume_all audio_pause_all audio_is_playing audio_is_paused audio_exists audio_sound_set_track_position audio_sound_get_track_position audio_emitter_get_gain audio_emitter_get_pitch audio_emitter_get_x audio_emitter_get_y audio_emitter_get_z audio_emitter_get_vx audio_emitter_get_vy audio_emitter_get_vz audio_listener_set_position audio_listener_set_velocity audio_listener_set_orientation audio_listener_get_data audio_set_master_gain audio_get_master_gain audio_sound_get_gain audio_sound_get_pitch audio_get_name audio_sound_set_track_position audio_sound_get_track_position audio_create_stream audio_destroy_stream audio_create_sync_group audio_destroy_sync_group audio_play_in_sync_group audio_start_sync_group audio_stop_sync_group audio_pause_sync_group audio_resume_sync_group audio_sync_group_get_track_pos audio_sync_group_debug audio_sync_group_is_playing audio_debug audio_group_load audio_group_unload audio_group_is_loaded audio_group_load_progress audio_group_name audio_group_stop_all audio_group_set_gain audio_create_buffer_sound audio_free_buffer_sound audio_create_play_queue audio_free_play_queue audio_queue_sound audio_get_recorder_count audio_get_recorder_info audio_start_recording audio_stop_recording audio_sound_get_listener_mask audio_emitter_get_listener_mask audio_get_listener_mask audio_sound_set_listener_mask audio_emitter_set_listener_mask audio_set_listener_mask audio_get_listener_count audio_get_listener_info audio_system show_message show_message_async clickable_add clickable_add_ext clickable_change clickable_change_ext clickable_delete clickable_exists clickable_set_style show_question show_question_async get_integer get_string get_integer_async get_string_async get_login_async get_open_filename get_save_filename get_open_filename_ext get_save_filename_ext show_error highscore_clear highscore_add highscore_value highscore_name draw_highscore sprite_exists sprite_get_name sprite_get_number sprite_get_width sprite_get_height sprite_get_xoffset sprite_get_yoffset sprite_get_bbox_left sprite_get_bbox_right sprite_get_bbox_top sprite_get_bbox_bottom sprite_save sprite_save_strip sprite_set_cache_size sprite_set_cache_size_ext sprite_get_tpe sprite_prefetch sprite_prefetch_multi sprite_flush sprite_flush_multi sprite_set_speed sprite_get_speed_type sprite_get_speed font_exists font_get_name font_get_fontname font_get_bold font_get_italic font_get_first font_get_last font_get_size font_set_cache_size path_exists path_get_name path_get_length path_get_time path_get_kind path_get_closed path_get_precision path_get_number path_get_point_x path_get_point_y path_get_point_speed path_get_x path_get_y path_get_speed script_exists script_get_name timeline_add timeline_delete timeline_clear timeline_exists timeline_get_name timeline_moment_clear timeline_moment_add_script timeline_size timeline_max_moment object_exists object_get_name object_get_sprite object_get_solid object_get_visible object_get_persistent object_get_mask object_get_parent object_get_physics object_is_ancestor room_exists room_get_name sprite_set_offset sprite_duplicate sprite_assign sprite_merge sprite_add sprite_replace sprite_create_from_surface sprite_add_from_surface sprite_delete sprite_set_alpha_from_sprite sprite_collision_mask font_add_enable_aa font_add_get_enable_aa font_add font_add_sprite font_add_sprite_ext font_replace font_replace_sprite font_replace_sprite_ext font_delete path_set_kind path_set_closed path_set_precision path_add path_assign path_duplicate path_append path_delete path_add_point path_insert_point path_change_point path_delete_point path_clear_points path_reverse path_mirror path_flip path_rotate path_rescale path_shift script_execute object_set_sprite object_set_solid object_set_visible object_set_persistent object_set_mask room_set_width room_set_height room_set_persistent room_set_background_colour room_set_background_color room_set_view room_set_viewport room_get_viewport room_set_view_enabled room_add room_duplicate room_assign room_instance_add room_instance_clear room_get_camera room_set_camera asset_get_index asset_get_type file_text_open_from_string file_text_open_read file_text_open_write file_text_open_append file_text_close file_text_write_string file_text_write_real file_text_writeln file_text_read_string file_text_read_real file_text_readln file_text_eof file_text_eoln file_exists file_delete file_rename file_copy directory_exists directory_create directory_destroy file_find_first file_find_next file_find_close file_attributes filename_name filename_path filename_dir filename_drive filename_ext filename_change_ext file_bin_open file_bin_rewrite file_bin_close file_bin_position file_bin_size file_bin_seek file_bin_write_byte file_bin_read_byte parameter_count parameter_string environment_get_variable ini_open_from_string ini_open ini_close ini_read_string ini_read_real ini_write_string ini_write_real ini_key_exists ini_section_exists ini_key_delete ini_section_delete ds_set_precision ds_exists ds_stack_create ds_stack_destroy ds_stack_clear ds_stack_copy ds_stack_size ds_stack_empty ds_stack_push ds_stack_pop ds_stack_top ds_stack_write ds_stack_read ds_queue_create ds_queue_destroy ds_queue_clear ds_queue_copy ds_queue_size ds_queue_empty ds_queue_enqueue ds_queue_dequeue ds_queue_head ds_queue_tail ds_queue_write ds_queue_read ds_list_create ds_list_destroy ds_list_clear ds_list_copy ds_list_size ds_list_empty ds_list_add ds_list_insert ds_list_replace ds_list_delete ds_list_find_index ds_list_find_value ds_list_mark_as_list ds_list_mark_as_map ds_list_sort ds_list_shuffle ds_list_write ds_list_read ds_list_set ds_map_create ds_map_destroy ds_map_clear ds_map_copy ds_map_size ds_map_empty ds_map_add ds_map_add_list ds_map_add_map ds_map_replace ds_map_replace_map ds_map_replace_list ds_map_delete ds_map_exists ds_map_find_value ds_map_find_previous ds_map_find_next ds_map_find_first ds_map_find_last ds_map_write ds_map_read ds_map_secure_save ds_map_secure_load ds_map_secure_load_buffer ds_map_secure_save_buffer ds_map_set ds_priority_create ds_priority_destroy ds_priority_clear ds_priority_copy ds_priority_size ds_priority_empty ds_priority_add ds_priority_change_priority ds_priority_find_priority ds_priority_delete_value ds_priority_delete_min ds_priority_find_min ds_priority_delete_max ds_priority_find_max ds_priority_write ds_priority_read ds_grid_create ds_grid_destroy ds_grid_copy ds_grid_resize ds_grid_width ds_grid_height ds_grid_clear ds_grid_set ds_grid_add ds_grid_multiply ds_grid_set_region ds_grid_add_region ds_grid_multiply_region ds_grid_set_disk ds_grid_add_disk ds_grid_multiply_disk ds_grid_set_grid_region ds_grid_add_grid_region ds_grid_multiply_grid_region ds_grid_get ds_grid_get_sum ds_grid_get_max ds_grid_get_min ds_grid_get_mean ds_grid_get_disk_sum ds_grid_get_disk_min ds_grid_get_disk_max ds_grid_get_disk_mean ds_grid_value_exists ds_grid_value_x ds_grid_value_y ds_grid_value_disk_exists ds_grid_value_disk_x ds_grid_value_disk_y ds_grid_shuffle ds_grid_write ds_grid_read ds_grid_sort ds_grid_set ds_grid_get effect_create_below effect_create_above effect_clear part_type_create part_type_destroy part_type_exists part_type_clear part_type_shape part_type_sprite part_type_size part_type_scale part_type_orientation part_type_life part_type_step part_type_death part_type_speed part_type_direction part_type_gravity part_type_colour1 part_type_colour2 part_type_colour3 part_type_colour_mix part_type_colour_rgb part_type_colour_hsv part_type_color1 part_type_color2 part_type_color3 part_type_color_mix part_type_color_rgb part_type_color_hsv part_type_alpha1 part_type_alpha2 part_type_alpha3 part_type_blend part_system_create part_system_create_layer part_system_destroy part_system_exists part_system_clear part_system_draw_order part_system_depth part_system_position part_system_automatic_update part_system_automatic_draw part_system_update part_system_drawit part_system_get_layer part_system_layer part_particles_create part_particles_create_colour part_particles_create_color part_particles_clear part_particles_count part_emitter_create part_emitter_destroy part_emitter_destroy_all part_emitter_exists part_emitter_clear part_emitter_region part_emitter_burst part_emitter_stream external_call external_define external_free window_handle window_device matrix_get matrix_set matrix_build_identity matrix_build matrix_build_lookat matrix_build_projection_ortho matrix_build_projection_perspective matrix_build_projection_perspective_fov matrix_multiply matrix_transform_vertex matrix_stack_push matrix_stack_pop matrix_stack_multiply matrix_stack_set matrix_stack_clear matrix_stack_top matrix_stack_is_empty browser_input_capture os_get_config os_get_info os_get_language os_get_region os_lock_orientation display_get_dpi_x display_get_dpi_y display_set_gui_size display_set_gui_maximise display_set_gui_maximize device_mouse_dbclick_enable display_set_timing_method display_get_timing_method display_set_sleep_margin display_get_sleep_margin virtual_key_add virtual_key_hide virtual_key_delete virtual_key_show draw_enable_drawevent draw_enable_swf_aa draw_set_swf_aa_level draw_get_swf_aa_level draw_texture_flush draw_flush gpu_set_blendenable gpu_set_ztestenable gpu_set_zfunc gpu_set_zwriteenable gpu_set_lightingenable gpu_set_fog gpu_set_cullmode gpu_set_blendmode gpu_set_blendmode_ext gpu_set_blendmode_ext_sepalpha gpu_set_colorwriteenable gpu_set_colourwriteenable gpu_set_alphatestenable gpu_set_alphatestref gpu_set_alphatestfunc gpu_set_texfilter gpu_set_texfilter_ext gpu_set_texrepeat gpu_set_texrepeat_ext gpu_set_tex_filter gpu_set_tex_filter_ext gpu_set_tex_repeat gpu_set_tex_repeat_ext gpu_set_tex_mip_filter gpu_set_tex_mip_filter_ext gpu_set_tex_mip_bias gpu_set_tex_mip_bias_ext gpu_set_tex_min_mip gpu_set_tex_min_mip_ext gpu_set_tex_max_mip gpu_set_tex_max_mip_ext gpu_set_tex_max_aniso gpu_set_tex_max_aniso_ext gpu_set_tex_mip_enable gpu_set_tex_mip_enable_ext gpu_get_blendenable gpu_get_ztestenable gpu_get_zfunc gpu_get_zwriteenable gpu_get_lightingenable gpu_get_fog gpu_get_cullmode gpu_get_blendmode gpu_get_blendmode_ext gpu_get_blendmode_ext_sepalpha gpu_get_blendmode_src gpu_get_blendmode_dest gpu_get_blendmode_srcalpha gpu_get_blendmode_destalpha gpu_get_colorwriteenable gpu_get_colourwriteenable gpu_get_alphatestenable gpu_get_alphatestref gpu_get_alphatestfunc gpu_get_texfilter gpu_get_texfilter_ext gpu_get_texrepeat gpu_get_texrepeat_ext gpu_get_tex_filter gpu_get_tex_filter_ext gpu_get_tex_repeat gpu_get_tex_repeat_ext gpu_get_tex_mip_filter gpu_get_tex_mip_filter_ext gpu_get_tex_mip_bias gpu_get_tex_mip_bias_ext gpu_get_tex_min_mip gpu_get_tex_min_mip_ext gpu_get_tex_max_mip gpu_get_tex_max_mip_ext gpu_get_tex_max_aniso gpu_get_tex_max_aniso_ext gpu_get_tex_mip_enable gpu_get_tex_mip_enable_ext gpu_push_state gpu_pop_state gpu_get_state gpu_set_state draw_light_define_ambient draw_light_define_direction draw_light_define_point draw_light_enable draw_set_lighting draw_light_get_ambient draw_light_get draw_get_lighting shop_leave_rating url_get_domain url_open url_open_ext url_open_full get_timer achievement_login achievement_logout achievement_post achievement_increment achievement_post_score achievement_available achievement_show_achievements achievement_show_leaderboards achievement_load_friends achievement_load_leaderboard achievement_send_challenge achievement_load_progress achievement_reset achievement_login_status achievement_get_pic achievement_show_challenge_notifications achievement_get_challenges achievement_event achievement_show achievement_get_info cloud_file_save cloud_string_save cloud_synchronise ads_enable ads_disable ads_setup ads_engagement_launch ads_engagement_available ads_engagement_active ads_event ads_event_preload ads_set_reward_callback ads_get_display_height ads_get_display_width ads_move ads_interstitial_available ads_interstitial_display device_get_tilt_x device_get_tilt_y device_get_tilt_z device_is_keypad_open device_mouse_check_button device_mouse_check_button_pressed device_mouse_check_button_released device_mouse_x device_mouse_y device_mouse_raw_x device_mouse_raw_y device_mouse_x_to_gui device_mouse_y_to_gui iap_activate iap_status iap_enumerate_products iap_restore_all iap_acquire iap_consume iap_product_details iap_purchase_details facebook_init facebook_login facebook_status facebook_graph_request facebook_dialog facebook_logout facebook_launch_offerwall facebook_post_message facebook_send_invite facebook_user_id facebook_accesstoken facebook_check_permission facebook_request_read_permissions facebook_request_publish_permissions gamepad_is_supported gamepad_get_device_count gamepad_is_connected gamepad_get_description gamepad_get_button_threshold gamepad_set_button_threshold gamepad_get_axis_deadzone gamepad_set_axis_deadzone gamepad_button_count gamepad_button_check gamepad_button_check_pressed gamepad_button_check_released gamepad_button_value gamepad_axis_count gamepad_axis_value gamepad_set_vibration gamepad_set_colour gamepad_set_color os_is_paused window_has_focus code_is_compiled http_get http_get_file http_post_string http_request json_encode json_decode zip_unzip load_csv base64_encode base64_decode md5_string_unicode md5_string_utf8 md5_file os_is_network_connected sha1_string_unicode sha1_string_utf8 sha1_file os_powersave_enable analytics_event analytics_event_ext win8_livetile_tile_notification win8_livetile_tile_clear win8_livetile_badge_notification win8_livetile_badge_clear win8_livetile_queue_enable win8_secondarytile_pin win8_secondarytile_badge_notification win8_secondarytile_delete win8_livetile_notification_begin win8_livetile_notification_secondary_begin win8_livetile_notification_expiry win8_livetile_notification_tag win8_livetile_notification_text_add win8_livetile_notification_image_add win8_livetile_notification_end win8_appbar_enable win8_appbar_add_element win8_appbar_remove_element win8_settingscharm_add_entry win8_settingscharm_add_html_entry win8_settingscharm_add_xaml_entry win8_settingscharm_set_xaml_property win8_settingscharm_get_xaml_property win8_settingscharm_remove_entry win8_share_image win8_share_screenshot win8_share_file win8_share_url win8_share_text win8_search_enable win8_search_disable win8_search_add_suggestions win8_device_touchscreen_available win8_license_initialize_sandbox win8_license_trial_version winphone_license_trial_version winphone_tile_title winphone_tile_count winphone_tile_back_title winphone_tile_back_content winphone_tile_back_content_wide winphone_tile_front_image winphone_tile_front_image_small winphone_tile_front_image_wide winphone_tile_back_image winphone_tile_back_image_wide winphone_tile_background_colour winphone_tile_background_color winphone_tile_icon_image winphone_tile_small_icon_image winphone_tile_wide_content winphone_tile_cycle_images winphone_tile_small_background_image physics_world_create physics_world_gravity physics_world_update_speed physics_world_update_iterations physics_world_draw_debug physics_pause_enable physics_fixture_create physics_fixture_set_kinematic physics_fixture_set_density physics_fixture_set_awake physics_fixture_set_restitution physics_fixture_set_friction physics_fixture_set_collision_group physics_fixture_set_sensor physics_fixture_set_linear_damping physics_fixture_set_angular_damping physics_fixture_set_circle_shape physics_fixture_set_box_shape physics_fixture_set_edge_shape physics_fixture_set_polygon_shape physics_fixture_set_chain_shape physics_fixture_add_point physics_fixture_bind physics_fixture_bind_ext physics_fixture_delete physics_apply_force physics_apply_impulse physics_apply_angular_impulse physics_apply_local_force physics_apply_local_impulse physics_apply_torque physics_mass_properties physics_draw_debug physics_test_overlap physics_remove_fixture physics_set_friction physics_set_density physics_set_restitution physics_get_friction physics_get_density physics_get_restitution physics_joint_distance_create physics_joint_rope_create physics_joint_revolute_create physics_joint_prismatic_create physics_joint_pulley_create physics_joint_wheel_create physics_joint_weld_create physics_joint_friction_create physics_joint_gear_create physics_joint_enable_motor physics_joint_get_value physics_joint_set_value physics_joint_delete physics_particle_create physics_particle_delete physics_particle_delete_region_circle physics_particle_delete_region_box physics_particle_delete_region_poly physics_particle_set_flags physics_particle_set_category_flags physics_particle_draw physics_particle_draw_ext physics_particle_count physics_particle_get_data physics_particle_get_data_particle physics_particle_group_begin physics_particle_group_circle physics_particle_group_box physics_particle_group_polygon physics_particle_group_add_point physics_particle_group_end physics_particle_group_join physics_particle_group_delete physics_particle_group_count physics_particle_group_get_data physics_particle_group_get_mass physics_particle_group_get_inertia physics_particle_group_get_centre_x physics_particle_group_get_centre_y physics_particle_group_get_vel_x physics_particle_group_get_vel_y physics_particle_group_get_ang_vel physics_particle_group_get_x physics_particle_group_get_y physics_particle_group_get_angle physics_particle_set_group_flags physics_particle_get_group_flags physics_particle_get_max_count physics_particle_get_radius physics_particle_get_density physics_particle_get_damping physics_particle_get_gravity_scale physics_particle_set_max_count physics_particle_set_radius physics_particle_set_density physics_particle_set_damping physics_particle_set_gravity_scale network_create_socket network_create_socket_ext network_create_server network_create_server_raw network_connect network_connect_raw network_send_packet network_send_raw network_send_broadcast network_send_udp network_send_udp_raw network_set_timeout network_set_config network_resolve network_destroy buffer_create buffer_write buffer_read buffer_seek buffer_get_surface buffer_set_surface buffer_delete buffer_exists buffer_get_type buffer_get_alignment buffer_poke buffer_peek buffer_save buffer_save_ext buffer_load buffer_load_ext buffer_load_partial buffer_copy buffer_fill buffer_get_size buffer_tell buffer_resize buffer_md5 buffer_sha1 buffer_base64_encode buffer_base64_decode buffer_base64_decode_ext buffer_sizeof buffer_get_address buffer_create_from_vertex_buffer buffer_create_from_vertex_buffer_ext buffer_copy_from_vertex_buffer buffer_async_group_begin buffer_async_group_option buffer_async_group_end buffer_load_async buffer_save_async gml_release_mode gml_pragma steam_activate_overlay steam_is_overlay_enabled steam_is_overlay_activated steam_get_persona_name steam_initialised steam_is_cloud_enabled_for_app steam_is_cloud_enabled_for_account steam_file_persisted steam_get_quota_total steam_get_quota_free steam_file_write steam_file_write_file steam_file_read steam_file_delete steam_file_exists steam_file_size steam_file_share steam_is_screenshot_requested steam_send_screenshot steam_is_user_logged_on steam_get_user_steam_id steam_user_owns_dlc steam_user_installed_dlc steam_set_achievement steam_get_achievement steam_clear_achievement steam_set_stat_int steam_set_stat_float steam_set_stat_avg_rate steam_get_stat_int steam_get_stat_float steam_get_stat_avg_rate steam_reset_all_stats steam_reset_all_stats_achievements steam_stats_ready steam_create_leaderboard steam_upload_score steam_upload_score_ext steam_download_scores_around_user steam_download_scores steam_download_friends_scores steam_upload_score_buffer steam_upload_score_buffer_ext steam_current_game_language steam_available_languages steam_activate_overlay_browser steam_activate_overlay_user steam_activate_overlay_store steam_get_user_persona_name steam_get_app_id steam_get_user_account_id steam_ugc_download steam_ugc_create_item steam_ugc_start_item_update steam_ugc_set_item_title steam_ugc_set_item_description steam_ugc_set_item_visibility steam_ugc_set_item_tags steam_ugc_set_item_content steam_ugc_set_item_preview steam_ugc_submit_item_update steam_ugc_get_item_update_progress steam_ugc_subscribe_item steam_ugc_unsubscribe_item steam_ugc_num_subscribed_items steam_ugc_get_subscribed_items steam_ugc_get_item_install_info steam_ugc_get_item_update_info steam_ugc_request_item_details steam_ugc_create_query_user steam_ugc_create_query_user_ex steam_ugc_create_query_all steam_ugc_create_query_all_ex steam_ugc_query_set_cloud_filename_filter steam_ugc_query_set_match_any_tag steam_ugc_query_set_search_text steam_ugc_query_set_ranked_by_trend_days steam_ugc_query_add_required_tag steam_ugc_query_add_excluded_tag steam_ugc_query_set_return_long_description steam_ugc_query_set_return_total_only steam_ugc_query_set_allow_cached_response steam_ugc_send_query shader_set shader_get_name shader_reset shader_current shader_is_compiled shader_get_sampler_index shader_get_uniform shader_set_uniform_i shader_set_uniform_i_array shader_set_uniform_f shader_set_uniform_f_array shader_set_uniform_matrix shader_set_uniform_matrix_array shader_enable_corner_id texture_set_stage texture_get_texel_width texture_get_texel_height shaders_are_supported vertex_format_begin vertex_format_end vertex_format_delete vertex_format_add_position vertex_format_add_position_3d vertex_format_add_colour vertex_format_add_color vertex_format_add_normal vertex_format_add_texcoord vertex_format_add_textcoord vertex_format_add_custom vertex_create_buffer vertex_create_buffer_ext vertex_delete_buffer vertex_begin vertex_end vertex_position vertex_position_3d vertex_colour vertex_color vertex_argb vertex_texcoord vertex_normal vertex_float1 vertex_float2 vertex_float3 vertex_float4 vertex_ubyte4 vertex_submit vertex_freeze vertex_get_number vertex_get_buffer_size vertex_create_buffer_from_buffer vertex_create_buffer_from_buffer_ext push_local_notification push_get_first_local_notification push_get_next_local_notification push_cancel_local_notification skeleton_animation_set skeleton_animation_get skeleton_animation_mix skeleton_animation_set_ext skeleton_animation_get_ext skeleton_animation_get_duration skeleton_animation_get_frames skeleton_animation_clear skeleton_skin_set skeleton_skin_get skeleton_attachment_set skeleton_attachment_get skeleton_attachment_create skeleton_collision_draw_set skeleton_bone_data_get skeleton_bone_data_set skeleton_bone_state_get skeleton_bone_state_set skeleton_get_minmax skeleton_get_num_bounds skeleton_get_bounds skeleton_animation_get_frame skeleton_animation_set_frame draw_skeleton draw_skeleton_time draw_skeleton_instance draw_skeleton_collision skeleton_animation_list skeleton_skin_list skeleton_slot_data layer_get_id layer_get_id_at_depth layer_get_depth layer_create layer_destroy layer_destroy_instances layer_add_instance layer_has_instance layer_set_visible layer_get_visible layer_exists layer_x layer_y layer_get_x layer_get_y layer_hspeed layer_vspeed layer_get_hspeed layer_get_vspeed layer_script_begin layer_script_end layer_shader layer_get_script_begin layer_get_script_end layer_get_shader layer_set_target_room layer_get_target_room layer_reset_target_room layer_get_all layer_get_all_elements layer_get_name layer_depth layer_get_element_layer layer_get_element_type layer_element_move layer_force_draw_depth layer_is_draw_depth_forced layer_get_forced_depth layer_background_get_id layer_background_exists layer_background_create layer_background_destroy layer_background_visible layer_background_change layer_background_sprite layer_background_htiled layer_background_vtiled layer_background_stretch layer_background_yscale layer_background_xscale layer_background_blend layer_background_alpha layer_background_index layer_background_speed layer_background_get_visible layer_background_get_sprite layer_background_get_htiled layer_background_get_vtiled layer_background_get_stretch layer_background_get_yscale layer_background_get_xscale layer_background_get_blend layer_background_get_alpha layer_background_get_index layer_background_get_speed layer_sprite_get_id layer_sprite_exists layer_sprite_create layer_sprite_destroy layer_sprite_change layer_sprite_index layer_sprite_speed layer_sprite_xscale layer_sprite_yscale layer_sprite_angle layer_sprite_blend layer_sprite_alpha layer_sprite_x layer_sprite_y layer_sprite_get_sprite layer_sprite_get_index layer_sprite_get_speed layer_sprite_get_xscale layer_sprite_get_yscale layer_sprite_get_angle layer_sprite_get_blend layer_sprite_get_alpha layer_sprite_get_x layer_sprite_get_y layer_tilemap_get_id layer_tilemap_exists layer_tilemap_create layer_tilemap_destroy tilemap_tileset tilemap_x tilemap_y tilemap_set tilemap_set_at_pixel tilemap_get_tileset tilemap_get_tile_width tilemap_get_tile_height tilemap_get_width tilemap_get_height tilemap_get_x tilemap_get_y tilemap_get tilemap_get_at_pixel tilemap_get_cell_x_at_pixel tilemap_get_cell_y_at_pixel tilemap_clear draw_tilemap draw_tile tilemap_set_global_mask tilemap_get_global_mask tilemap_set_mask tilemap_get_mask tilemap_get_frame tile_set_empty tile_set_index tile_set_flip tile_set_mirror tile_set_rotate tile_get_empty tile_get_index tile_get_flip tile_get_mirror tile_get_rotate layer_tile_exists layer_tile_create layer_tile_destroy layer_tile_change layer_tile_xscale layer_tile_yscale layer_tile_blend layer_tile_alpha layer_tile_x layer_tile_y layer_tile_region layer_tile_visible layer_tile_get_sprite layer_tile_get_xscale layer_tile_get_yscale layer_tile_get_blend layer_tile_get_alpha layer_tile_get_x layer_tile_get_y layer_tile_get_region layer_tile_get_visible layer_instance_get_instance instance_activate_layer instance_deactivate_layer camera_create camera_create_view camera_destroy camera_apply camera_get_active camera_get_default camera_set_default camera_set_view_mat camera_set_proj_mat camera_set_update_script camera_set_begin_script camera_set_end_script camera_set_view_pos camera_set_view_size camera_set_view_speed camera_set_view_border camera_set_view_angle camera_set_view_target camera_get_view_mat camera_get_proj_mat camera_get_update_script camera_get_begin_script camera_get_end_script camera_get_view_x camera_get_view_y camera_get_view_width camera_get_view_height camera_get_view_speed_x camera_get_view_speed_y camera_get_view_border_x camera_get_view_border_y camera_get_view_angle camera_get_view_target view_get_camera view_get_visible view_get_xport view_get_yport view_get_wport view_get_hport view_get_surface_id view_set_camera view_set_visible view_set_xport view_set_yport view_set_wport view_set_hport view_set_surface_id gesture_drag_time gesture_drag_distance gesture_flick_speed gesture_double_tap_time gesture_double_tap_distance gesture_pinch_distance gesture_pinch_angle_towards gesture_pinch_angle_away gesture_rotate_time gesture_rotate_angle gesture_tap_count gesture_get_drag_time gesture_get_drag_distance gesture_get_flick_speed gesture_get_double_tap_time gesture_get_double_tap_distance gesture_get_pinch_distance gesture_get_pinch_angle_towards gesture_get_pinch_angle_away gesture_get_rotate_time gesture_get_rotate_angle gesture_get_tap_count keyboard_virtual_show keyboard_virtual_hide keyboard_virtual_status keyboard_virtual_height",
literal:"self other all noone global local undefined pointer_invalid pointer_null path_action_stop path_action_restart path_action_continue path_action_reverse true false pi GM_build_date GM_version GM_runtime_version timezone_local timezone_utc gamespeed_fps gamespeed_microseconds ev_create ev_destroy ev_step ev_alarm ev_keyboard ev_mouse ev_collision ev_other ev_draw ev_draw_begin ev_draw_end ev_draw_pre ev_draw_post ev_keypress ev_keyrelease ev_trigger ev_left_button ev_right_button ev_middle_button ev_no_button ev_left_press ev_right_press ev_middle_press ev_left_release ev_right_release ev_middle_release ev_mouse_enter ev_mouse_leave ev_mouse_wheel_up ev_mouse_wheel_down ev_global_left_button ev_global_right_button ev_global_middle_button ev_global_left_press ev_global_right_press ev_global_middle_press ev_global_left_release ev_global_right_release ev_global_middle_release ev_joystick1_left ev_joystick1_right ev_joystick1_up ev_joystick1_down ev_joystick1_button1 ev_joystick1_button2 ev_joystick1_button3 ev_joystick1_button4 ev_joystick1_button5 ev_joystick1_button6 ev_joystick1_button7 ev_joystick1_button8 ev_joystick2_left ev_joystick2_right ev_joystick2_up ev_joystick2_down ev_joystick2_button1 ev_joystick2_button2 ev_joystick2_button3 ev_joystick2_button4 ev_joystick2_button5 ev_joystick2_button6 ev_joystick2_button7 ev_joystick2_button8 ev_outside ev_boundary ev_game_start ev_game_end ev_room_start ev_room_end ev_no_more_lives ev_animation_end ev_end_of_path ev_no_more_health ev_close_button ev_user0 ev_user1 ev_user2 ev_user3 ev_user4 ev_user5 ev_user6 ev_user7 ev_user8 ev_user9 ev_user10 ev_user11 ev_user12 ev_user13 ev_user14 ev_user15 ev_step_normal ev_step_begin ev_step_end ev_gui ev_gui_begin ev_gui_end ev_cleanup ev_gesture ev_gesture_tap ev_gesture_double_tap ev_gesture_drag_start ev_gesture_dragging ev_gesture_drag_end ev_gesture_flick ev_gesture_pinch_start ev_gesture_pinch_in ev_gesture_pinch_out ev_gesture_pinch_end ev_gesture_rotate_start ev_gesture_rotating ev_gesture_rotate_end ev_global_gesture_tap ev_global_gesture_double_tap ev_global_gesture_drag_start ev_global_gesture_dragging ev_global_gesture_drag_end ev_global_gesture_flick ev_global_gesture_pinch_start ev_global_gesture_pinch_in ev_global_gesture_pinch_out ev_global_gesture_pinch_end ev_global_gesture_rotate_start ev_global_gesture_rotating ev_global_gesture_rotate_end vk_nokey vk_anykey vk_enter vk_return vk_shift vk_control vk_alt vk_escape vk_space vk_backspace vk_tab vk_pause vk_printscreen vk_left vk_right vk_up vk_down vk_home vk_end vk_delete vk_insert vk_pageup vk_pagedown vk_f1 vk_f2 vk_f3 vk_f4 vk_f5 vk_f6 vk_f7 vk_f8 vk_f9 vk_f10 vk_f11 vk_f12 vk_numpad0 vk_numpad1 vk_numpad2 vk_numpad3 vk_numpad4 vk_numpad5 vk_numpad6 vk_numpad7 vk_numpad8 vk_numpad9 vk_divide vk_multiply vk_subtract vk_add vk_decimal vk_lshift vk_lcontrol vk_lalt vk_rshift vk_rcontrol vk_ralt mb_any mb_none mb_left mb_right mb_middle c_aqua c_black c_blue c_dkgray c_fuchsia c_gray c_green c_lime c_ltgray c_maroon c_navy c_olive c_purple c_red c_silver c_teal c_white c_yellow c_orange fa_left fa_center fa_right fa_top fa_middle fa_bottom pr_pointlist pr_linelist pr_linestrip pr_trianglelist pr_trianglestrip pr_trianglefan bm_complex bm_normal bm_add bm_max bm_subtract bm_zero bm_one bm_src_colour bm_inv_src_colour bm_src_color bm_inv_src_color bm_src_alpha bm_inv_src_alpha bm_dest_alpha bm_inv_dest_alpha bm_dest_colour bm_inv_dest_colour bm_dest_color bm_inv_dest_color bm_src_alpha_sat tf_point tf_linear tf_anisotropic mip_off mip_on mip_markedonly audio_falloff_none audio_falloff_inverse_distance audio_falloff_inverse_distance_clamped audio_falloff_linear_distance audio_falloff_linear_distance_clamped audio_falloff_exponent_distance audio_falloff_exponent_distance_clamped audio_old_system audio_new_system audio_mono audio_stereo audio_3d cr_default cr_none cr_arrow cr_cross cr_beam cr_size_nesw cr_size_ns cr_size_nwse cr_size_we cr_uparrow cr_hourglass cr_drag cr_appstart cr_handpoint cr_size_all spritespeed_framespersecond spritespeed_framespergameframe asset_object asset_unknown asset_sprite asset_sound asset_room asset_path asset_script asset_font asset_timeline asset_tiles asset_shader fa_readonly fa_hidden fa_sysfile fa_volumeid fa_directory fa_archive ds_type_map ds_type_list ds_type_stack ds_type_queue ds_type_grid ds_type_priority ef_explosion ef_ring ef_ellipse ef_firework ef_smoke ef_smokeup ef_star ef_spark ef_flare ef_cloud ef_rain ef_snow pt_shape_pixel pt_shape_disk pt_shape_square pt_shape_line pt_shape_star pt_shape_circle pt_shape_ring pt_shape_sphere pt_shape_flare pt_shape_spark pt_shape_explosion pt_shape_cloud pt_shape_smoke pt_shape_snow ps_distr_linear ps_distr_gaussian ps_distr_invgaussian ps_shape_rectangle ps_shape_ellipse ps_shape_diamond ps_shape_line ty_real ty_string dll_cdecl dll_stdcall matrix_view matrix_projection matrix_world os_win32 os_windows os_macosx os_ios os_android os_symbian os_linux os_unknown os_winphone os_tizen os_win8native os_wiiu os_3ds os_psvita os_bb10 os_ps4 os_xboxone os_ps3 os_xbox360 os_uwp os_tvos os_switch browser_not_a_browser browser_unknown browser_ie browser_firefox browser_chrome browser_safari browser_safari_mobile browser_opera browser_tizen browser_edge browser_windows_store browser_ie_mobile device_ios_unknown device_ios_iphone device_ios_iphone_retina device_ios_ipad device_ios_ipad_retina device_ios_iphone5 device_ios_iphone6 device_ios_iphone6plus device_emulator device_tablet display_landscape display_landscape_flipped display_portrait display_portrait_flipped tm_sleep tm_countvsyncs of_challenge_win of_challen ge_lose of_challenge_tie leaderboard_type_number leaderboard_type_time_mins_secs cmpfunc_never cmpfunc_less cmpfunc_equal cmpfunc_lessequal cmpfunc_greater cmpfunc_notequal cmpfunc_greaterequal cmpfunc_always cull_noculling cull_clockwise cull_counterclockwise lighttype_dir lighttype_point iap_ev_storeload iap_ev_product iap_ev_purchase iap_ev_consume iap_ev_restore iap_storeload_ok iap_storeload_failed iap_status_uninitialised iap_status_unavailable iap_status_loading iap_status_available iap_status_processing iap_status_restoring iap_failed iap_unavailable iap_available iap_purchased iap_canceled iap_refunded fb_login_default fb_login_fallback_to_webview fb_login_no_fallback_to_webview fb_login_forcing_webview fb_login_use_system_account fb_login_forcing_safari phy_joint_anchor_1_x phy_joint_anchor_1_y phy_joint_anchor_2_x phy_joint_anchor_2_y phy_joint_reaction_force_x phy_joint_reaction_force_y phy_joint_reaction_torque phy_joint_motor_speed phy_joint_angle phy_joint_motor_torque phy_joint_max_motor_torque phy_joint_translation phy_joint_speed phy_joint_motor_force phy_joint_max_motor_force phy_joint_length_1 phy_joint_length_2 phy_joint_damping_ratio phy_joint_frequency phy_joint_lower_angle_limit phy_joint_upper_angle_limit phy_joint_angle_limits phy_joint_max_length phy_joint_max_torque phy_joint_max_force phy_debug_render_aabb phy_debug_render_collision_pairs phy_debug_render_coms phy_debug_render_core_shapes phy_debug_render_joints phy_debug_render_obb phy_debug_render_shapes phy_particle_flag_water phy_particle_flag_zombie phy_particle_flag_wall phy_particle_flag_spring phy_particle_flag_elastic phy_particle_flag_viscous phy_particle_flag_powder phy_particle_flag_tensile phy_particle_flag_colourmixing phy_particle_flag_colormixing phy_particle_group_flag_solid phy_particle_group_flag_rigid phy_particle_data_flag_typeflags phy_particle_data_flag_position phy_particle_data_flag_velocity phy_particle_data_flag_colour phy_particle_data_flag_color phy_particle_data_flag_category achievement_our_info achievement_friends_info achievement_leaderboard_info achievement_achievement_info achievement_filter_all_players achievement_filter_friends_only achievement_filter_favorites_only achievement_type_achievement_challenge achievement_type_score_challenge achievement_pic_loaded achievement_show_ui achievement_show_profile achievement_show_leaderboard achievement_show_achievement achievement_show_bank achievement_show_friend_picker achievement_show_purchase_prompt network_socket_tcp network_socket_udp network_socket_bluetooth network_type_connect network_type_disconnect network_type_data network_type_non_blocking_connect network_config_connect_timeout network_config_use_non_blocking_socket network_config_enable_reliable_udp network_config_disable_reliable_udp buffer_fixed buffer_grow buffer_wrap buffer_fast buffer_vbuffer buffer_network buffer_u8 buffer_s8 buffer_u16 buffer_s16 buffer_u32 buffer_s32 buffer_u64 buffer_f16 buffer_f32 buffer_f64 buffer_bool buffer_text buffer_string buffer_surface_copy buffer_seek_start buffer_seek_relative buffer_seek_end buffer_generalerror buffer_outofspace buffer_outofbounds buffer_invalidtype text_type button_type input_type ANSI_CHARSET DEFAULT_CHARSET EASTEUROPE_CHARSET RUSSIAN_CHARSET SYMBOL_CHARSET SHIFTJIS_CHARSET HANGEUL_CHARSET GB2312_CHARSET CHINESEBIG5_CHARSET JOHAB_CHARSET HEBREW_CHARSET ARABIC_CHARSET GREEK_CHARSET TURKISH_CHARSET VIETNAMESE_CHARSET THAI_CHARSET MAC_CHARSET BALTIC_CHARSET OEM_CHARSET gp_face1 gp_face2 gp_face3 gp_face4 gp_shoulderl gp_shoulderr gp_shoulderlb gp_shoulderrb gp_select gp_start gp_stickl gp_stickr gp_padu gp_padd gp_padl gp_padr gp_axislh gp_axislv gp_axisrh gp_axisrv ov_friends ov_community ov_players ov_settings ov_gamegroup ov_achievements lb_sort_none lb_sort_ascending lb_sort_descending lb_disp_none lb_disp_numeric lb_disp_time_sec lb_disp_time_ms ugc_result_success ugc_filetype_community ugc_filetype_microtrans ugc_visibility_public ugc_visibility_friends_only ugc_visibility_private ugc_query_RankedByVote ugc_query_RankedByPublicationDate ugc_query_AcceptedForGameRankedByAcceptanceDate ugc_query_RankedByTrend ugc_query_FavoritedByFriendsRankedByPublicationDate ugc_query_CreatedByFriendsRankedByPublicationDate ugc_query_RankedByNumTimesReported ugc_query_CreatedByFollowedUsersRankedByPublicationDate ugc_query_NotYetRated ugc_query_RankedByTotalVotesAsc ugc_query_RankedByVotesUp ugc_query_RankedByTextSearch ugc_sortorder_CreationOrderDesc ugc_sortorder_CreationOrderAsc ugc_sortorder_TitleAsc ugc_sortorder_LastUpdatedDesc ugc_sortorder_SubscriptionDateDesc ugc_sortorder_VoteScoreDesc ugc_sortorder_ForModeration ugc_list_Published ugc_list_VotedOn ugc_list_VotedUp ugc_list_VotedDown ugc_list_WillVoteLater ugc_list_Favorited ugc_list_Subscribed ugc_list_UsedOrPlayed ugc_list_Followed ugc_match_Items ugc_match_Items_Mtx ugc_match_Items_ReadyToUse ugc_match_Collections ugc_match_Artwork ugc_match_Videos ugc_match_Screenshots ugc_match_AllGuides ugc_match_WebGuides ugc_match_IntegratedGuides ugc_match_UsableInGame ugc_match_ControllerBindings vertex_usage_position vertex_usage_colour vertex_usage_color vertex_usage_normal vertex_usage_texcoord vertex_usage_textcoord vertex_usage_blendweight vertex_usage_blendindices vertex_usage_psize vertex_usage_tangent vertex_usage_binormal vertex_usage_fog vertex_usage_depth vertex_usage_sample vertex_type_float1 vertex_type_float2 vertex_type_float3 vertex_type_float4 vertex_type_colour vertex_type_color vertex_type_ubyte4 layerelementtype_undefined layerelementtype_background layerelementtype_instance layerelementtype_oldtilemap layerelementtype_sprite layerelementtype_tilemap layerelementtype_particlesystem layerelementtype_tile tile_rotate tile_flip tile_mirror tile_index_mask kbv_type_default kbv_type_ascii kbv_type_url kbv_type_email kbv_type_numbers kbv_type_phone kbv_type_phone_name kbv_returnkey_default kbv_returnkey_go kbv_returnkey_google kbv_returnkey_join kbv_returnkey_next kbv_returnkey_route kbv_returnkey_search kbv_returnkey_send kbv_returnkey_yahoo kbv_returnkey_done kbv_returnkey_continue kbv_returnkey_emergency kbv_autocapitalize_none kbv_autocapitalize_words kbv_autocapitalize_sentences kbv_autocapitalize_characters",
symbol:"argument_relative argument argument0 argument1 argument2 argument3 argument4 argument5 argument6 argument7 argument8 argument9 argument10 argument11 argument12 argument13 argument14 argument15 argument_count x|0 y|0 xprevious yprevious xstart ystart hspeed vspeed direction speed friction gravity gravity_direction path_index path_position path_positionprevious path_speed path_scale path_orientation path_endaction object_index id solid persistent mask_index instance_count instance_id room_speed fps fps_real current_time current_year current_month current_day current_weekday current_hour current_minute current_second alarm timeline_index timeline_position timeline_speed timeline_running timeline_loop room room_first room_last room_width room_height room_caption room_persistent score lives health show_score show_lives show_health caption_score caption_lives caption_health event_type event_number event_object event_action application_surface gamemaker_pro gamemaker_registered gamemaker_version error_occurred error_last debug_mode keyboard_key keyboard_lastkey keyboard_lastchar keyboard_string mouse_x mouse_y mouse_button mouse_lastbutton cursor_sprite visible sprite_index sprite_width sprite_height sprite_xoffset sprite_yoffset image_number image_index image_speed depth image_xscale image_yscale image_angle image_alpha image_blend bbox_left bbox_right bbox_top bbox_bottom layer background_colour background_showcolour background_color background_showcolor view_enabled view_current view_visible view_xview view_yview view_wview view_hview view_xport view_yport view_wport view_hport view_angle view_hborder view_vborder view_hspeed view_vspeed view_object view_surface_id view_camera game_id game_display_name game_project_name game_save_id working_directory temp_directory program_directory browser_width browser_height os_type os_device os_browser os_version display_aa async_load delta_time webgl_enabled event_data iap_data phy_rotation phy_position_x phy_position_y phy_angular_velocity phy_linear_velocity_x phy_linear_velocity_y phy_speed_x phy_speed_y phy_speed phy_angular_damping phy_linear_damping phy_bullet phy_fixed_rotation phy_active phy_mass phy_inertia phy_com_x phy_com_y phy_dynamic phy_kinematic phy_sleeping phy_collision_points phy_collision_x phy_collision_y phy_col_normal_x phy_col_normal_y phy_position_xprevious phy_position_yprevious"
},
@@ -1826,7 +1833,7 @@
end:"[ \\t]*=",excludeEnd:!0},A={className:"variable",keywords:C,begin:E,
relevance:0,contains:[N,I]
},e="[A-Za-z\u0410-\u042f\u0430-\u044f\u0451\u0401_][A-Za-z\u0410-\u042f\u0430-\u044f\u0451\u0401_0-9]*\\("
-;return{name:"ISBL",aliases:["isbl"],case_insensitive:!0,keywords:C,
+;return{name:"ISBL",case_insensitive:!0,keywords:C,
illegal:"\\$|\\?|%|,|;$|~|#|@|</",contains:[{className:"function",begin:e,
end:"\\)$",returnBegin:!0,keywords:C,illegal:"[\\[\\]\\|\\$\\?%,~#@]",
contains:[{className:"title",keywords:{$pattern:E,
@@ -1869,7 +1876,7 @@
contains:[s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,r,e.C_BLOCK_COMMENT_MODE]
},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},r,s]}}})());
hljs.registerLanguage("javascript",(()=>{"use strict"
-;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
+;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
;function r(e){return t("(?=",e,")")}function t(...e){return e.map((e=>{
return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return i=>{
const c=e,o={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,
@@ -1877,10 +1884,10 @@
;"<"!==s?">"===s&&(((e,{after:n})=>{const a="</"+e[0].slice(1)
;return-1!==e.input.indexOf(a,n)})(e,{after:a
})||n.ignoreMatch()):n.ignoreMatch()}},l={$pattern:e,keyword:n,literal:a,
-built_in:s},b="\\.([0-9](_?[0-9])*)",g="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",d={
+built_in:s},g="\\.([0-9](_?[0-9])*)",b="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",d={
className:"number",variants:[{
-begin:`(\\b(${g})((${b})|\\.)?|(${b}))[eE][+-]?([0-9](_?[0-9])*)\\b`},{
-begin:`\\b(${g})\\b((${b})\\b|\\.)?|(${b})\\b`},{
+begin:`(\\b(${b})((${g})|\\.)?|(${g}))[eE][+-]?([0-9](_?[0-9])*)\\b`},{
+begin:`\\b(${b})\\b((${g})\\b|\\.)?|(${g})\\b`},{
begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{
begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{
begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{
@@ -1889,30 +1896,30 @@
returnEnd:!1,contains:[i.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},_={
begin:"css`",end:"",starts:{end:"`",returnEnd:!1,
contains:[i.BACKSLASH_ESCAPE,E],subLanguage:"css"}},m={className:"string",
-begin:"`",end:"`",contains:[i.BACKSLASH_ESCAPE,E]},N={className:"comment",
+begin:"`",end:"`",contains:[i.BACKSLASH_ESCAPE,E]},y={className:"comment",
variants:[i.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",
end:"\\}",relevance:0},{className:"variable",begin:c+"(?=\\s*(-)|$)",
endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
}),i.C_BLOCK_COMMENT_MODE,i.C_LINE_COMMENT_MODE]
-},y=[i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,u,_,m,d,i.REGEXP_MODE]
-;E.contains=y.concat({begin:/\{/,end:/\}/,keywords:l,contains:["self"].concat(y)
-});const f=[].concat(N,E.contains),A=f.concat([{begin:/\(/,end:/\)/,keywords:l,
-contains:["self"].concat(f)}]),p={className:"params",begin:/\(/,end:/\)/,
-excludeBegin:!0,excludeEnd:!0,keywords:l,contains:A};return{name:"Javascript",
-aliases:["js","jsx","mjs","cjs"],keywords:l,exports:{PARAMS_CONTAINS:A},
+},N=[i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,u,_,m,d,i.REGEXP_MODE]
+;E.contains=N.concat({begin:/\{/,end:/\}/,keywords:l,contains:["self"].concat(N)
+});const A=[].concat(y,E.contains),f=A.concat([{begin:/\(/,end:/\)/,keywords:l,
+contains:["self"].concat(A)}]),p={className:"params",begin:/\(/,end:/\)/,
+excludeBegin:!0,excludeEnd:!0,keywords:l,contains:f};return{name:"Javascript",
+aliases:["js","jsx","mjs","cjs"],keywords:l,exports:{PARAMS_CONTAINS:f},
illegal:/#(?![$_A-z])/,contains:[i.SHEBANG({label:"shebang",binary:"node",
relevance:5}),{label:"use_strict",className:"meta",relevance:10,
begin:/^\s*['"]use (strict|asm)['"]/
-},i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,u,_,m,N,d,{
+},i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,u,_,m,y,d,{
begin:t(/[{,\n]\s*/,r(t(/(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,c+"\\s*:"))),
relevance:0,contains:[{className:"attr",begin:c+r("\\s*:"),relevance:0}]},{
begin:"("+i.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
-keywords:"return throw case",contains:[N,i.REGEXP_MODE,{className:"function",
+keywords:"return throw case",contains:[y,i.REGEXP_MODE,{className:"function",
begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+i.UNDERSCORE_IDENT_RE+")\\s*=>",
returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{
begin:i.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0
-},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:A}]}]
+},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:f}]}]
},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{
variants:[{begin:"<>",end:"</>"},{begin:o.begin,"on:begin":o.isTrulyOpeningTag,
end:o.end}],subLanguage:"xml",contains:[{begin:o.begin,end:o.end,skip:!0,
@@ -1992,9 +1999,9 @@
},o=a,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={
variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d],
-{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{
-relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]
-}),e.C_LINE_COMMENT_MODE,b,{className:"keyword",
+{name:"Kotlin",aliases:["kt","kts"],keywords:n,
+contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
+begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword",
begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
begin:/@\w+/}]}},i,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$",
returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
@@ -2155,13 +2162,13 @@
},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE,a].concat(t),
illegal:";$|^\\[|^=|&|\\{"}}})());
hljs.registerLanguage("livescript",(()=>{"use strict"
-;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
+;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
;return t=>{const r={
keyword:e.concat(["then","unless","until","loop","of","by","when","and","or","is","isnt","not","it","that","otherwise","from","to","til","fallthrough","case","enum","native","list","map","__hasProp","__extends","__slice","__bind","__indexOf"]),
literal:n.concat(["yes","no","on","off","it","that","void"]),
built_in:a.concat(["npm","print"])
-},s="[A-Za-z$_](?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*",i=t.inherit(t.TITLE_MODE,{
-begin:s}),o={className:"subst",begin:/#\{/,end:/\}/,keywords:r},c={
+},i="[A-Za-z$_](?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*",s=t.inherit(t.TITLE_MODE,{
+begin:i}),o={className:"subst",begin:/#\{/,end:/\}/,keywords:r},c={
className:"subst",begin:/#[A-Za-z$_]/,end:/(?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*/,
keywords:r},l=[t.BINARY_NUMBER_MODE,{className:"number",
begin:"(\\b0[xX][a-fA-F0-9_]+)|(\\b\\d(\\d|_\\d)*(\\.(\\d(\\d|_\\d)*)?)?(_*[eE]([-+]\\d(_\\d|\\d)*)?)?[_a-z]*)",
@@ -2172,21 +2179,21 @@
contains:[t.BACKSLASH_ESCAPE,o,c]},{begin:/\\/,end:/(\s|$)/,excludeEnd:!0}]},{
className:"regexp",variants:[{begin:"//",end:"//[gim]*",
contains:[o,t.HASH_COMMENT_MODE]},{
-begin:/\/(?![ *])(\\.|[^\\\n])*?\/[gim]*(?=\W)/}]},{begin:"@"+s},{begin:"``",
+begin:/\/(?![ *])(\\.|[^\\\n])*?\/[gim]*(?=\W)/}]},{begin:"@"+i},{begin:"``",
end:"``",excludeBegin:!0,excludeEnd:!0,subLanguage:"javascript"}];o.contains=l
;const d={className:"params",begin:"\\(",returnBegin:!0,contains:[{begin:/\(/,
end:/\)/,keywords:r,contains:["self"].concat(l)}]};return{name:"LiveScript",
aliases:["ls"],keywords:r,illegal:/\/\*/,
contains:l.concat([t.COMMENT("\\/\\*","\\*\\/"),t.HASH_COMMENT_MODE,{
-begin:"(#=>|=>|\\|>>|-?->|!->)"},{className:"function",contains:[i,d],
+begin:"(#=>|=>|\\|>>|-?->|!->)"},{className:"function",contains:[s,d],
returnBegin:!0,variants:[{
-begin:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\)\\s*)?\\B->\\*?",end:"->\\*?"},{
-begin:"("+s+"\\s*(?:=|:=)\\s*)?!?(\\(.*\\)\\s*)?\\B[-~]{1,2}>\\*?",
+begin:"("+i+"\\s*(?:=|:=)\\s*)?(\\(.*\\)\\s*)?\\B->\\*?",end:"->\\*?"},{
+begin:"("+i+"\\s*(?:=|:=)\\s*)?!?(\\(.*\\)\\s*)?\\B[-~]{1,2}>\\*?",
end:"[-~]{1,2}>\\*?"},{
-begin:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\)\\s*)?\\B!?[-~]{1,2}>\\*?",
+begin:"("+i+"\\s*(?:=|:=)\\s*)?(\\(.*\\)\\s*)?\\B!?[-~]{1,2}>\\*?",
end:"!?[-~]{1,2}>\\*?"}]},{className:"class",beginKeywords:"class",end:"$",
illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,
-illegal:/[:="\[\]]/,contains:[i]},i]},{begin:s+":",end:":",returnBegin:!0,
+illegal:/[:="\[\]]/,contains:[s]},s]},{begin:i+":",end:":",returnBegin:!0,
returnEnd:!0,relevance:0}])}}})());
hljs.registerLanguage("llvm",(()=>{"use strict";function e(...e){
return e.map((e=>{return(n=e)?"string"==typeof n?n:n.source:null;var n
@@ -2440,8 +2447,7 @@
begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|\\{",returnBegin:!0,contains:[{
className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],
illegal:"[^\\s\\}]"}}})());
-hljs.registerLanguage("nim",(()=>{"use strict";return e=>({name:"Nim",
-aliases:["nim"],keywords:{
+hljs.registerLanguage("nim",(()=>{"use strict";return e=>({name:"Nim",keywords:{
keyword:"addr and as asm bind block break case cast const continue converter discard distinct div do elif else end enum except export finally for from func generic if import in include interface is isnot iterator let macro method mixin mod nil not notin object of or out proc ptr raise ref return shl shr static template try tuple type using var when while with without xor yield",
literal:"shared guarded stdin stdout stderr result true false",
built_in:"int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 bool char string cstring pointer expr stmt void auto any range array openarray varargs seq set clong culong cchar cschar cshort cint csize clonglong cfloat cdouble clongdouble cuchar cushort cuint culonglong cstringarray semistatic"
@@ -2646,27 +2652,32 @@
begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,
contains:e.QUOTE_STRING_MODE.contains.concat(a)}),l={className:"string",
contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(n,{begin:"b'",end:"'"
-}),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},c={
-variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},s={
-keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 new object or private protected public real return string switch throw trait try unset use var void while xor yield",
+}),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},s={className:"number",variants:[{
+begin:"\\b0b[01]+(?:_[01]+)*\\b"},{begin:"\\b0o[0-7]+(?:_[0-7]+)*\\b"},{
+begin:"\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b"},{
+begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?"
+}],relevance:0},c={
+keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 mixed new object or private protected public real return string switch throw trait try unset use var void while xor yield",
literal:"false null true",
-built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"
-};return{aliases:["php","php3","php4","php5","php6","php7","php8"],
-case_insensitive:!0,keywords:s,
+built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"
+};return{aliases:["php3","php4","php5","php6","php7","php8"],
+case_insensitive:!0,keywords:c,
contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]
}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]
}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,
keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},r,{
begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",
relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,
-illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{begin:"=>"},{
-className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,
-keywords:s,contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,c]}]},{className:"class",
-beginKeywords:"class interface",relevance:0,end:/\{/,excludeEnd:!0,
-illegal:/[:($"]/,contains:[{beginKeywords:"extends implements"
-},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",relevance:0,end:";",
-illegal:/[.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",
-relevance:0,end:";",contains:[e.UNDERSCORE_TITLE_MODE]},l,c]}}})());
+illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{
+begin:"=>",endsParent:!0},{className:"params",begin:"\\(",end:"\\)",
+excludeBegin:!0,excludeEnd:!0,keywords:c,
+contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,s]}]},{className:"class",variants:[{
+beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",
+illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{
+beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{
+beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,
+contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",
+contains:[e.UNDERSCORE_TITLE_MODE]},l,s]}}})());
hljs.registerLanguage("php-template",(()=>{"use strict";return n=>({
name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,
subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',
@@ -2964,8 +2975,8 @@
}]},s={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,i,{
className:"variable",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]}]},t={
className:"string",begin:/'/,end:/'/};return{name:"Microtik RouterOS script",
-aliases:["routeros","mikrotik"],case_insensitive:!0,keywords:{
-$pattern:/:?[\w-]+/,literal:n,
+aliases:["mikrotik"],case_insensitive:!0,keywords:{$pattern:/:?[\w-]+/,
+literal:n,
keyword:r+" :"+r.split(" ").join(" :")+" :"+"global local beep delay put len typeof pick log time set find environment terminal error execute parse resolve toarray tobool toid toip toip6 tonum tostr totime".split(" ").join(" :")
},contains:[{variants:[{begin:/\/\*/,end:/\*\//},{begin:/\/\//,end:/$/},{
begin:/<\//,end:/>/}],illegal:/./},e.COMMENT("^#","$"),s,t,i,{
@@ -3018,7 +3029,7 @@
contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{endsParent:!0})],illegal:"[\\w\\d]"
},{begin:e.IDENT_RE+"::",keywords:{built_in:t}},{begin:"->"}]}}})());
hljs.registerLanguage("sas",(()=>{"use strict";return e=>({name:"SAS",
-aliases:["sas","SAS"],case_insensitive:!0,keywords:{
+aliases:["SAS"],case_insensitive:!0,keywords:{
literal:"null missing _all_ _automatic_ _character_ _infile_ _n_ _name_ _null_ _numeric_ _user_ _webout_",
meta:"do if then else end until while abort array attrib by call cards cards4 catname continue datalines datalines4 delete delim delimiter display dm drop endsas error file filename footnote format goto in infile informat input keep label leave length libname link list lostcard merge missing modify options output out page put redirect remove rename replace retain return select set skip startsas stop title update waitsas where window x systask add and alter as cascade check create delete describe distinct drop foreign from group having index insert into in key like message modify msgtype not null on or order primary references reset restrict select set table unique update validate view where"
},contains:[{className:"keyword",begin:/^\s*(proc [\w\d_]+|data|run|quit)[\s;]/
@@ -3110,10 +3121,10 @@
subLanguage:"bash"}}]})})());
hljs.registerLanguage("smali",(()=>{"use strict";return e=>{
const n=["add","and","cmp","cmpg","cmpl","const","div","double","float","goto","if","int","long","move","mul","neg","new","nop","not","or","rem","return","shl","shr","sput","sub","throw","ushr","xor"]
-;return{name:"Smali",aliases:["smali"],contains:[{className:"string",begin:'"',
-end:'"',relevance:0},e.COMMENT("#","$",{relevance:0}),{className:"keyword",
-variants:[{begin:"\\s*\\.end\\s[a-zA-Z0-9]*"},{begin:"^[ ]*\\.[a-zA-Z]*",
-relevance:0},{begin:"\\s:[a-zA-Z_0-9]*",relevance:0},{
+;return{name:"Smali",contains:[{className:"string",begin:'"',end:'"',relevance:0
+},e.COMMENT("#","$",{relevance:0}),{className:"keyword",variants:[{
+begin:"\\s*\\.end\\s[a-zA-Z0-9]*"},{begin:"^[ ]*\\.[a-zA-Z]*",relevance:0},{
+begin:"\\s:[a-zA-Z_0-9]*",relevance:0},{
begin:"\\s(transient|constructor|abstract|final|synthetic|public|private|protected|static|bridge|system)"
}]},{className:"built_in",variants:[{begin:"\\s("+n.join("|")+")\\s"},{
begin:"\\s("+n.join("|")+")((-|/)[a-zA-Z0-9]+)+\\s",relevance:10},{
@@ -3369,19 +3380,20 @@
end:"\\.\\.\\.$",subLanguage:"yaml",relevance:0},{className:"number",
begin:" (\\d+) "},{className:"symbol",variants:[{begin:"^ok"},{begin:"^not ok"}]
}]})})());
-hljs.registerLanguage("tcl",(()=>{"use strict";return e=>({name:"Tcl",
+hljs.registerLanguage("tcl",(()=>{"use strict";function e(...e){
+return e.map((e=>{return(a=e)?"string"==typeof a?a:a.source:null;var a
+})).join("")}return a=>{const t=/[a-zA-Z_][a-zA-Z0-9_]*/,r={className:"number",
+variants:[a.BINARY_NUMBER_MODE,a.C_NUMBER_MODE]};return{name:"Tcl",
aliases:["tk"],
keywords:"after append apply array auto_execok auto_import auto_load auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror binary break catch cd chan clock close concat continue dde dict encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent filename flush for foreach format gets glob global history http if incr info interp join lappend|10 lassign|10 lindex|10 linsert|10 list llength|10 load lrange|10 lrepeat|10 lreplace|10 lreverse|10 lsearch|10 lset|10 lsort|10 mathfunc mathop memory msgcat namespace open package parray pid pkg::create pkg_mkIndex platform platform::shell proc puts pwd read refchan regexp registry regsub|10 rename return safe scan seek set socket source split string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord tcl_wordBreakAfter tcl_wordBreakBefore tcltest tclvars tell time tm trace unknown unload unset update uplevel upvar variable vwait while",
-contains:[e.COMMENT(";[ \\t]*#","$"),e.COMMENT("^[ \\t]*#","$"),{
+contains:[a.COMMENT(";[ \\t]*#","$"),a.COMMENT("^[ \\t]*#","$"),{
beginKeywords:"proc",end:"[\\{]",excludeEnd:!0,contains:[{className:"title",
begin:"[ \\t\\n\\r]+(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",end:"[ \\t\\n\\r]",
-endsWithParent:!0,excludeEnd:!0}]},{excludeEnd:!0,variants:[{
-begin:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*\\(([a-zA-Z0-9_])*\\)",
-end:"[^a-zA-Z0-9_\\}\\$]"},{begin:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",
-end:"(\\))?[^a-zA-Z0-9_\\}\\$]"}]},{className:"string",
-contains:[e.BACKSLASH_ESCAPE],variants:[e.inherit(e.QUOTE_STRING_MODE,{
-illegal:null})]},{className:"number",
-variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]}]})})());
+endsWithParent:!0,excludeEnd:!0}]},{className:"variable",variants:[{
+begin:e(/\$/,(n=/::/,e("(",n,")?")),t,"(::",t,")*")},{
+begin:"\\$\\{(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",end:"\\}",contains:[r]}]},{
+className:"string",contains:[a.BACKSLASH_ESCAPE],
+variants:[a.inherit(a.QUOTE_STRING_MODE,{illegal:null})]},r]};var n}})());
hljs.registerLanguage("thrift",(()=>{"use strict";return e=>{
const t="bool byte i16 i32 i64 double string binary";return{name:"Thrift",
keywords:{
@@ -3424,7 +3436,7 @@
endsWithParent:!0,contains:[t,n],relevance:0}}]},{className:"template-variable",
begin:/\{\{/,end:/\}\}/,contains:["self",t,n]}]}}})());
hljs.registerLanguage("typescript",(()=>{"use strict"
-;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
+;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"])
;function t(e){return r("(?=",e,")")}function r(...e){return e.map((e=>{
return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")}return i=>{
const c={$pattern:e,
@@ -3450,27 +3462,27 @@
end:"\\}",keywords:l,contains:[]},E={begin:"html`",end:"",starts:{end:"`",
returnEnd:!1,contains:[i.BACKSLASH_ESCAPE,u],subLanguage:"xml"}},m={
begin:"css`",end:"",starts:{end:"`",returnEnd:!1,
-contains:[i.BACKSLASH_ESCAPE,u],subLanguage:"css"}},_={className:"string",
-begin:"`",end:"`",contains:[i.BACKSLASH_ESCAPE,u]},y={className:"comment",
+contains:[i.BACKSLASH_ESCAPE,u],subLanguage:"css"}},y={className:"string",
+begin:"`",end:"`",contains:[i.BACKSLASH_ESCAPE,u]},_={className:"comment",
variants:[i.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",
end:"\\}",relevance:0},{className:"variable",begin:c+"(?=\\s*(-)|$)",
endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
}),i.C_BLOCK_COMMENT_MODE,i.C_LINE_COMMENT_MODE]
-},p=[i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,E,m,_,g,i.REGEXP_MODE]
+},p=[i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,E,m,y,g,i.REGEXP_MODE]
;u.contains=p.concat({begin:/\{/,end:/\}/,keywords:l,contains:["self"].concat(p)
-});const N=[].concat(y,u.contains),f=N.concat([{begin:/\(/,end:/\)/,keywords:l,
+});const N=[].concat(_,u.contains),f=N.concat([{begin:/\(/,end:/\)/,keywords:l,
contains:["self"].concat(N)}]),A={className:"params",begin:/\(/,end:/\)/,
excludeBegin:!0,excludeEnd:!0,keywords:l,contains:f};return{name:"Javascript",
aliases:["js","jsx","mjs","cjs"],keywords:l,exports:{PARAMS_CONTAINS:f},
illegal:/#(?![$_A-z])/,contains:[i.SHEBANG({label:"shebang",binary:"node",
relevance:5}),{label:"use_strict",className:"meta",relevance:10,
begin:/^\s*['"]use (strict|asm)['"]/
-},i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,E,m,_,y,g,{
+},i.APOS_STRING_MODE,i.QUOTE_STRING_MODE,E,m,y,_,g,{
begin:r(/[{,\n]\s*/,t(r(/(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,c+"\\s*:"))),
relevance:0,contains:[{className:"attr",begin:c+t("\\s*:"),relevance:0}]},{
begin:"("+i.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
-keywords:"return throw case",contains:[y,i.REGEXP_MODE,{className:"function",
+keywords:"return throw case",contains:[_,i.REGEXP_MODE,{className:"function",
begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+i.UNDERSCORE_IDENT_RE+")\\s*=>",
returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{
begin:i.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0
@@ -3497,7 +3509,7 @@
}]),l(b,"shebang",i.SHEBANG()),l(b,"use_strict",{className:"meta",relevance:10,
begin:/^\s*['"]use strict['"]/
}),b.contains.find((e=>"function"===e.className)).relevance=0,Object.assign(b,{
-name:"TypeScript",aliases:["ts"]}),b}})());
+name:"TypeScript",aliases:["ts","tsx"]}),b}})());
hljs.registerLanguage("vala",(()=>{"use strict";return e=>({name:"Vala",
keywords:{
keyword:"char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double bool struct enum string void weak unowned owned async signal static abstract interface override virtual delegate if while do for foreach else switch case break default return try catch public private protected internal using new this get set const stdout stdin stderr var",
diff --git a/lib/mina/BUILD b/lib/mina/BUILD
index 70e7c1d..3f23263 100644
--- a/lib/mina/BUILD
+++ b/lib/mina/BUILD
@@ -13,6 +13,13 @@
)
java_library(
+ name = "sshd-sftp",
+ data = ["//lib:LICENSE-Apache2.0"],
+ visibility = ["//visibility:public"],
+ exports = ["@sshd-sftp//jar"],
+)
+
+java_library(
name = "eddsa",
data = ["//lib:LICENSE-CC0-1.0"],
visibility = ["//visibility:public"],
diff --git a/lib/nongoogle_test.sh b/lib/nongoogle_test.sh
index f596164..272cfa9 100755
--- a/lib/nongoogle_test.sh
+++ b/lib/nongoogle_test.sh
@@ -40,6 +40,7 @@
soy
sshd-mina
sshd-osgi
+sshd-sftp
testcontainers
truth
truth-java8-extension
diff --git a/modules/jgit b/modules/jgit
index 9bfb0f3..c82818e 160000
--- a/modules/jgit
+++ b/modules/jgit
@@ -1 +1 @@
-Subproject commit 9bfb0f3a4ec856dcbebb477a1ee8803a3c47c194
+Subproject commit c82818e0e02a9d1bd979d27bd342bb05661150d4
diff --git a/package.json b/package.json
index fc4161b..f5eafee 100644
--- a/package.json
+++ b/package.json
@@ -3,25 +3,25 @@
"version": "3.1.0-SNAPSHOT",
"description": "Gerrit Code Review",
"dependencies": {
- "@bazel/rollup": "^3.2.0",
- "@bazel/terser": "^3.2.0",
- "@bazel/typescript": "^3.2.0"
+ "@bazel/rollup": "^3.4.0",
+ "@bazel/terser": "^3.4.0",
+ "@bazel/typescript": "^3.4.0"
},
"devDependencies": {
- "@typescript-eslint/eslint-plugin": "^4.11.0",
- "eslint": "^7.16.0",
+ "@typescript-eslint/eslint-plugin": "^4.22.0",
+ "eslint": "^7.24.0",
"eslint-config-google": "^0.14.0",
- "eslint-plugin-html": "^6.1.1",
+ "eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.22.1",
- "eslint-plugin-jsdoc": "^30.7.9",
+ "eslint-plugin-jsdoc": "^32.3.0",
"eslint-plugin-node": "^11.1.0",
- "eslint-plugin-prettier": "^3.3.0",
- "gts": "^3.0.3",
+ "eslint-plugin-prettier": "^3.4.0",
+ "gts": "^3.1.0",
"polymer-cli": "^1.9.11",
- "prettier": "2.0.5",
- "rollup": "^2.3.4",
- "terser": "^4.8.0",
- "typescript": "4.0.5"
+ "prettier": "2.2.1",
+ "rollup": "^2.45.2",
+ "terser": "^5.6.1",
+ "typescript": "4.1.4"
},
"scripts": {
"clean": "git clean -fdx && bazel clean --expunge",
diff --git a/plugins/BUILD b/plugins/BUILD
index 943471a..353283b 100644
--- a/plugins/BUILD
+++ b/plugins/BUILD
@@ -58,6 +58,7 @@
"//java/com/google/gerrit/util/logging",
"//lib/antlr:java-runtime",
"//lib/auto:auto-value-annotations",
+ "//lib/auto:auto-value-gson",
"//lib/commons:compress",
"//lib/commons:dbcp",
"//lib/commons:lang",
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index 740c35a..30c774f 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit 740c35ae36f44748b3c91e60ee7dcb2fb6e99549
+Subproject commit 30c774f30c1709f71efc250a195dd6fb50c7503b
diff --git a/plugins/delete-project b/plugins/delete-project
index bfe159d..549de03 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit bfe159d3007db0f07e967473b53f679ba8f432df
+Subproject commit 549de033d60b13aaeef45ce5c4bf42be39506268
diff --git a/plugins/replication b/plugins/replication
index 14766e7..93e61dc 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 14766e75f91886ab48951035d59a78c8c3f07471
+Subproject commit 93e61dc64debe42eab454e6c268f9c4ee22a78bc
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index 2fb9e5c..c6e6cd9 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -116,7 +116,7 @@
the command line:
```sh
-./polygerrit-ui/run-server.sh --plugins=plugins/my_plugin/static/my_plugin.js,plugins/my_plugin/static/my_plugin.html
+./polygerrit-ui/run-server.sh --plugins=plugins/my_plugin/static/my_plugin.js
```
If any issues occured, please refer to the Troubleshooting section at the bottom or contact the team!
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index a3da3cf..faf126c 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -82,7 +82,7 @@
],
// https://eslint.org/docs/rules/new-cap
'new-cap': ['error', {
- capIsNewExceptions: ['Polymer', 'GestureEventListeners'],
+ capIsNewExceptions: ['Polymer'],
capIsNewExceptionPattern: '^.*Mixin$',
}],
// https://eslint.org/docs/rules/no-console
@@ -313,7 +313,10 @@
},
},
{
- files: ['*_test.ts'],
+ files: [
+ '*_test.ts',
+ 'test-utils.ts',
+ ],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
diff --git a/polygerrit-ui/app/api/annotation.ts b/polygerrit-ui/app/api/annotation.ts
index e58bdd5..bd4f399 100644
--- a/polygerrit-ui/app/api/annotation.ts
+++ b/polygerrit-ui/app/api/annotation.ts
@@ -14,8 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {CoverageRange, GrDiffLine, Side} from './diff';
-import {StyleObject} from './styles';
+import {CoverageRange, Side} from './diff';
/**
* This is the callback object that Gerrit calls once for each diff. Gerrit
@@ -37,61 +36,8 @@
change?: unknown
) => Promise<Array<CoverageRange>>;
-export type AnnotationCallback = (ctx: AnnotationContext) => void;
-
-/**
- * This object is passed to the plugin from Gerrit for each line of a diff that
- * is being rendered. The plugin can then call annotateRange() or
- * annotateLineNumber() to apply additional styles to the diff.
- */
-export interface AnnotationContext {
- /** Set by Gerrit and consumed by the plugin provided AddLayerFunc. */
- readonly changeNum: number;
- /** Set by Gerrit and consumed by the plugin provided AddLayerFunc. */
- readonly path: string;
- /** Set by Gerrit and consumed by the plugin provided AddLayerFunc. */
- readonly line: GrDiffLine;
- /** Set by Gerrit and consumed by the plugin provided AddLayerFunc. */
- readonly contentEl: HTMLElement;
- /** Set by Gerrit and consumed by the plugin provided AddLayerFunc. */
- readonly lineNumberEl: HTMLElement;
-
- /**
- * Can be called by the plugin to style a part of the given line of the
- * context.
- *
- * @param offset The char offset where the update starts.
- * @param length The number of chars that the update covers.
- * @param styleObject The style object for the range.
- * @param side The side of the update. ('left' or 'right')
- */
- annotateRange(
- offset: number,
- length: number,
- styleObject: StyleObject,
- side: string
- ): void;
-
- /**
- * Can be called by the plugin to style a part of the given line of the
- * context.
- *
- * @param styleObject The style object for the range.
- * @param side The side of the update. ('left' or 'right')
- */
- annotateLineNumber(styleObject: StyleObject, side: string): void;
-}
-
export interface AnnotationPluginApi {
/**
- * Registers a callback for applying annotations. Gerrit will call the
- * callback for every line of every file that is rendered and pass the
- * information about the file and line as an AnnotationContext, which also
- * provides methods for the plugin to style the content.
- */
- setLayer(callback: AnnotationCallback): AnnotationPluginApi;
-
- /**
* The specified function will be called when a gr-diff component is built,
* and feeds the returned coverage data into the diff. Optional.
*
@@ -102,28 +48,6 @@
setCoverageProvider(coverageProvider: CoverageProvider): AnnotationPluginApi;
/**
- * Returns a checkbox HTMLElement that can be used to toggle annotations
- * on/off. The checkbox will be initially disabled. Plugins should enable it
- * when data is ready and should add a click handler to toggle CSS on/off.
- *
- * Note1: Calling this method from multiple plugins will only work for the
- * 1st call. It will print an error message for all subsequent calls
- * and will not invoke their onAttached functions.
- * Note2: This method will be deprecated and eventually removed when
- * https://bugs.chromium.org/p/gerrit/issues/detail?id=8077 is
- * implemented.
- *
- * @param checkboxLabel Will be used as the label for the checkbox.
- * Optional. "Enable" is used if this is not specified.
- * @param onAttached The function that will be called
- * when the checkbox is attached to the page.
- */
- enableToggleCheckbox(
- checkboxLabel: string,
- onAttached: (checkboxEl: Element | null) => void
- ): AnnotationPluginApi;
-
- /**
* For plugins notifying Gerrit about new annotations being ready to be
* applied for a certain range. Gerrit will then re-render the relevant lines
* of the diff and call back to the layer annotation function that was
diff --git a/polygerrit-ui/app/api/change-metadata.ts b/polygerrit-ui/app/api/change-metadata.ts
deleted file mode 100644
index effe661..0000000
--- a/polygerrit-ui/app/api/change-metadata.ts
+++ /dev/null
@@ -1,20 +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.
- */
-
-export interface ChangeMetadataPluginApi {
- onLabelsChanged(callback: (value: unknown) => void): ChangeMetadataPluginApi;
-}
diff --git a/polygerrit-ui/app/api/change-reply.ts b/polygerrit-ui/app/api/change-reply.ts
index 37c96ee..6016004 100644
--- a/polygerrit-ui/app/api/change-reply.ts
+++ b/polygerrit-ui/app/api/change-reply.ts
@@ -29,8 +29,6 @@
setLabelValue(label: string, value: string): void;
- send(includeComments?: boolean): void;
-
addReplyTextChangedCallback(handler: ReplyChangedCallback): void;
addLabelValuesChangedCallback(handler: LabelsChangedCallback): void;
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index 4a5ef7e..f20eec8 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -46,7 +46,11 @@
export interface ChangeData {
changeNumber: number;
patchsetNumber: number;
+ patchsetSha: string;
repo: string;
+ commmitMessage?: string;
+ /* TODO(brohlfs): Add dep to Rest API types and replace type by ChangeInfo. */
+ changeInfo: unknown;
}
export interface ChecksProvider {
@@ -219,6 +223,8 @@
name: string;
tooltip?: string;
/**
+ * TODO: Maybe drop this property? Do we really need it?
+ *
* Primary actions will get a more prominent treatment in the UI. For example
* primary actions might be rendered as buttons versus just menu entries in
* an overflow menu.
@@ -364,11 +370,14 @@
color?: TagColor;
}
-// TBD: Add more ...
// TBD: Clarify standard colors for common tags.
export enum TagColor {
- GRAY,
- GREEN,
+ GRAY = 'gray',
+ YELLOW = 'yellow',
+ PINK = 'pink',
+ PURPLE = 'purple',
+ CYAN = 'cyan',
+ BROWN = 'brown',
}
export interface Link {
@@ -376,6 +385,8 @@
url: string;
tooltip?: string;
/**
+ * TODO: Maybe drop this property? Do we really need it?
+ *
* Primary links will get a more prominent treatment in the UI, e.g. being
* always visible in the results table or also showing up in the change page
* summary of checks.
@@ -384,8 +395,12 @@
icon: LinkIcon;
}
-// TBD: Add more ...
export enum LinkIcon {
EXTERNAL,
+ IMAGE,
+ HISTORY,
DOWNLOAD,
+ DOWNLOAD_MOBILE,
+ HELP_PAGE,
+ REPORT_BUG,
}
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index bd110c8..022492d 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -176,6 +176,8 @@
export declare interface RenderPreferences {
hide_left_side?: boolean;
disable_context_control_buttons?: boolean;
+ show_file_comment_button?: boolean;
+ hide_line_length_indicator?: boolean;
}
/**
@@ -249,6 +251,19 @@
lineNum: LineNumber;
}
+/** All types of button for expanding diff sections */
+export enum ContextButtonType {
+ ABOVE = 'above',
+ BELOW = 'below',
+ ALL = 'all',
+}
+
+/** Details to be externally accessed when expanding diffs */
+export declare interface DiffContextExpandedExternalDetail {
+ expandedLines: number;
+ buttonType: ContextButtonType;
+}
+
export enum GrDiffLineType {
ADD = 'add',
BOTH = 'both',
@@ -286,3 +301,43 @@
line: GrDiffLine
): void;
}
+
+/** Data used by GrAnnotation to generate elements. */
+export declare interface ElementSpec {
+ tagName: string;
+ attributes?: {[key: string]: unknown};
+}
+
+/** Used to annotate segments of an HTMLElement with a class string. */
+export declare interface GrAnnotation {
+ /**
+ * Annotates the [offset, offset+length) text segment in the parent with the
+ * element definition provided as arguments.
+ *
+ * @param parent the node whose contents will be annotated.
+ * If parent is Text then parent.parentNode must not be null
+ * @param offset the 0-based offset from which the annotation will
+ * start.
+ * @param length of the annotated text.
+ * @param elementSpec the spec to create the
+ * annotating element.
+ */
+ annotateWithElement(
+ el: HTMLElement,
+ start: number,
+ length: number,
+ elementSpec: ElementSpec
+ ): void;
+
+ /**
+ * Surrounds the element's text at specified range in an ANNOTATION_TAG
+ * element. If the element has child elements, the range is split and
+ * applied as deeply as possible.
+ */
+ annotateElement(
+ el: HTMLElement,
+ start: number,
+ length: number,
+ className: string
+ ): void;
+}
diff --git a/polygerrit-ui/app/api/settings.ts b/polygerrit-ui/app/api/embed.ts
similarity index 63%
rename from polygerrit-ui/app/api/settings.ts
rename to polygerrit-ui/app/api/embed.ts
index 03cf474..49be550 100644
--- a/polygerrit-ui/app/api/settings.ts
+++ b/polygerrit-ui/app/api/embed.ts
@@ -1,4 +1,9 @@
/**
+ * @fileoverview The API of class exported globally in embed/gr-diff.ts
+ *
+ * This is a mechanism to make classes accessible to separately compiled
+ * bundles, which cannot directly import the classes from their modules.
+ *
* @license
* Copyright (C) 2020 The Android Open Source Project
*
@@ -14,14 +19,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {HookApi} from './hook';
-export interface SettingsPluginApi {
- title(newTitle: string): SettingsPluginApi;
+import {GrAnnotation} from './diff';
- token(newToken: string): SettingsPluginApi;
-
- module(newModuleName: string): SettingsPluginApi;
-
- build(): HookApi;
+declare global {
+ interface Window {
+ grdiff: {
+ GrAnnotation: GrAnnotation;
+ };
+ }
}
diff --git a/polygerrit-ui/app/api/event-helper.ts b/polygerrit-ui/app/api/event-helper.ts
index c4a559b..16c327d 100644
--- a/polygerrit-ui/app/api/event-helper.ts
+++ b/polygerrit-ui/app/api/event-helper.ts
@@ -18,12 +18,6 @@
export interface EventHelperPluginApi {
/**
- * Add a callback to arbitrary event.
- * The callback may return false to prevent event bubbling.
- */
- on(event: string, callback: (event: Event) => boolean): UnsubscribeCallback;
-
- /**
* Alias for @see onClick
*/
onTap(callback: (event: Event) => boolean): UnsubscribeCallback;
@@ -33,17 +27,4 @@
* The callback may return false to prevent event bubbling.
*/
onClick(callback: (event: Event) => boolean): UnsubscribeCallback;
-
- /**
- * Alias for @see captureClick
- */
- captureTap(callback: (event: Event) => boolean): UnsubscribeCallback;
-
- /**
- * Add a callback to element click or touch ahead of normal flow.
- * Callback is installed on parent during capture phase.
- * https://www.w3.org/TR/DOM-Level-3-Events/#event-flow
- * The callback may return false to cancel regular event listeners.
- */
- captureClick(callback: (event: Event) => boolean): UnsubscribeCallback;
}
diff --git a/polygerrit-ui/app/api/plugin.ts b/polygerrit-ui/app/api/plugin.ts
index cd742a2..0aadb38 100644
--- a/polygerrit-ui/app/api/plugin.ts
+++ b/polygerrit-ui/app/api/plugin.ts
@@ -17,16 +17,11 @@
import {AdminPluginApi} from './admin';
import {AnnotationPluginApi} from './annotation';
import {AttributeHelperPluginApi} from './attribute-helper';
-import {ChangeMetadataPluginApi} from './change-metadata';
import {ChangeReplyPluginApi} from './change-reply';
import {ChecksPluginApi} from './checks';
import {EventHelperPluginApi} from './event-helper';
import {PopupPluginApi} from './popup';
-import {RepoPluginApi} from './repo';
import {ReportingPluginApi} from './reporting';
-import {SettingsPluginApi} from './settings';
-import {StylesPluginApi} from './styles';
-import {ThemePluginApi} from './theme';
import {ChangeActionsPluginApi} from './change-actions';
import {RestPluginApi} from './rest';
import {HookApi, RegisterOptions} from './hook';
@@ -59,7 +54,6 @@
annotationApi(): AnnotationPluginApi;
attributeHelper(element: Element): AttributeHelperPluginApi;
changeActions(): ChangeActionsPluginApi;
- changeMetadata(): ChangeMetadataPluginApi;
changeReply(): ChangeReplyPluginApi;
checks(): ChecksPluginApi;
eventHelper(element: Node): EventHelperPluginApi;
@@ -70,7 +64,6 @@
popup(): Promise<PopupPluginApi>;
popup(moduleName: string): Promise<PopupPluginApi>;
popup(moduleName?: string): Promise<PopupPluginApi | null>;
- project(): RepoPluginApi;
registerCustomComponent(
endpointName: string,
moduleName?: string,
@@ -86,7 +79,4 @@
restApi(): RestPluginApi;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
screen(screenName: string, moduleName?: string): any;
- settings(): SettingsPluginApi;
- styles(): StylesPluginApi;
- theme(): ThemePluginApi;
}
diff --git a/polygerrit-ui/app/api/repo.ts b/polygerrit-ui/app/api/repo.ts
deleted file mode 100644
index a626471..0000000
--- a/polygerrit-ui/app/api/repo.ts
+++ /dev/null
@@ -1,31 +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.
- */
-export type RepoCommandCallback = (
- repo?: string,
- /**
- * This is a ConfigInfo object as defined here:
- * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
- * We neither want to repeat it nor add a dependency on it here.
- */
- config?: unknown
-) => boolean;
-
-export interface RepoPluginApi {
- createCommand(title: string, callback: RepoCommandCallback): RepoPluginApi;
-
- onTap(callback: (event: Event) => boolean): RepoPluginApi;
-}
diff --git a/polygerrit-ui/app/api/styles.ts b/polygerrit-ui/app/api/styles.ts
deleted file mode 100644
index 233c3e2..0000000
--- a/polygerrit-ui/app/api/styles.ts
+++ /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.
- */
-
-export interface StyleObject {
- /**
- * Creates a new unique CSS class and injects it in a root node of the element
- * if it hasn't been added yet. A root node is an document or is the
- * associated shadowRoot. This class can be added to any element with the same
- * root node.
- */
- getClassName(element: Element): string;
-
- /**
- * Apply shared style to the element.
- */
- apply(element: Element): void;
-}
-
-export interface StylesPluginApi {
- css(ruleStr: string): StyleObject;
-}
diff --git a/polygerrit-ui/app/api/theme.ts b/polygerrit-ui/app/api/theme.ts
deleted file mode 100644
index 70ffcb3..0000000
--- a/polygerrit-ui/app/api/theme.ts
+++ /dev/null
@@ -1,20 +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.
- */
-
-export interface ThemePluginApi {
- setHeaderLogoAndTitle(logoUrl: string, title: string): void;
-}
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts
index be502f7..363f6e5 100644
--- a/polygerrit-ui/app/constants/constants.ts
+++ b/polygerrit-ui/app/constants/constants.ts
@@ -54,6 +54,7 @@
TAG_SET_ASSIGNEE = 'autogenerated:gerrit:setAssignee',
TAG_UNSET_ASSIGNEE = 'autogenerated:gerrit:deleteAssignee',
TAG_MERGED = 'autogenerated:gerrit:merged',
+ TAG_REVERT = 'autogenerated:gerrit:revert',
}
/**
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
new file mode 100644
index 0000000..0738825
--- /dev/null
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -0,0 +1,92 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http =//www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export enum LifeCycle {
+ PLUGIN_LIFE_CYCLE = 'Plugin life cycle',
+ STARTED_AS_USER = 'Started as user',
+ STARTED_AS_GUEST = 'Started as guest',
+ VISIBILILITY_HIDDEN = 'Visibility changed to hidden',
+ VISIBILILITY_VISIBLE = 'Visibility changed to visible',
+ EXTENSION_DETECTED = 'Extension detected',
+ PLUGINS_INSTALLED = 'Plugins installed',
+ USER_REFERRED_FROM = 'User referred from',
+}
+
+export enum Execution {
+ PLUGIN_API = 'plugin-api',
+ REACHABLE_CODE = 'reachable code',
+ METHOD_USED = 'method used',
+}
+
+export enum Timing {
+ // Time between the navigationStart timing and the ready call of gr-app.
+ APP_STARTED = 'App Started',
+ // Time from navigation to showing first content of change view.
+ CHANGE_DISPLAYED = 'ChangeDisplayed',
+ // Time from navigation to having loaded and presented all change data.
+ CHANGE_LOAD_FULL = 'ChangeFullyLoaded',
+ // Time from navigation to showing content of dashboard.
+ DASHBOARD_DISPLAYED = 'DashboardDisplayed',
+ // Time from navigation to showing full content of diff without highlighting layer
+ DIFF_VIEW_CONTENT_DISPLAYED = 'DiffViewOnlyContent',
+ // Time from navigation to showing viewport (> 120 lines) of diff with highlighting layer.
+ DIFF_VIEW_DISPLAYED = 'DiffViewDisplayed',
+ // Time from navigation to showing full content of diff
+ DIFF_VIEW_LOAD_FULL = 'DiffViewFullyLoaded',
+ // Time from navigation to showing initial content of the file list.
+ FILE_LIST_DISPLAYED = 'FileListDisplayed',
+ // Time from startup to having loaded all plugins.
+ PLUGINS_LOADED = 'PluginsLoaded',
+ // Time from startup to having loaded metrics plugin
+ METRICS_PLUGIN_LOADED = 'MetricsPluginLoaded',
+ // Time from startup to showing first content of change view.
+ STARTUP_CHANGE_DISPLAYED = 'StartupChangeDisplayed',
+ // Time from startup to having loaded and presented all change data.
+ STARTUP_CHANGE_LOAD_FULL = 'StartupChangeFullyLoaded',
+ // Time from startup to showing content of the dashboard.
+ STARTUP_DASHBOARD_DISPLAYED = 'StartupDashboardDisplayed',
+ // Time from startup to showing full content of diff without highlighting layer
+ STARTUP_DIFF_VIEW_CONTENT_DISPLAYED = 'StartupDiffViewOnlyContent',
+ // Time from startup to showing viewport (> 120 lines) of diff with highlighting layer.
+ STARTUP_DIFF_VIEW_DISPLAYED = 'StartupDiffViewDisplayed',
+ // Time from startup to showing full content of diff view.
+ STARTUP_DIFF_VIEW_LOAD_FULL = 'StartupDiffViewFullyLoaded',
+ // Time from startup to showing initial content of the file list.
+ STARTUP_FILE_LIST_DISPLAYED = 'StartupFileListDisplayed',
+ // Time from startup to when the webcomponentsready event is fired. If the event is fired from the webcomponents-lite polyfill, this may be arbitrarily long after the app has started.
+ WEB_COMPONENTS_READY = 'WebComponentsReady',
+ // Time to received all data for change view
+ CHANGE_DATA = 'ChangeDataLoaded',
+ // Time to compute and render first content of change view
+ CHANGE_RELOAD = 'ChangeReloaded',
+ // Time from clicking the [Send] button of the Reply Dialog to the time that the change has reloaded (core data)
+ SEND_REPLY = 'SendReply',
+ // The overall time to render a diff (excluding loading of data).
+ DIFF_TOTAL = 'Diff Total Render',
+ // The time to render the content off a diff (excluding loading of data or syntax highlighting).
+ DIFF_CONTENT = 'Diff Content Render',
+ // Time to compute and render the syntax highlighting of a diff.
+ DIFF_SYNTAX = 'Diff Syntax Render',
+ // Time to render a batch of rows in the file list. If there are very many files, this may be the first batch of rows that are rendered by default. If there are many files and the user clicks [Show More], this may be the batch of additional files that appear as a result.
+ FILE_RENDER = 'FileListRenderTime',
+ // This measures the same interval as FileListRenderTime, but the result is divided by the number of rows in the batch.
+ FILE_RENDER_AVG = 'FileListRenderTimePerFile',
+ // The time to expand some number of diffs in the file list (i.e. render their diffs, including syntax highlighting).
+ FILE_EXPAND_ALL = 'ExpandAllDiffs',
+ // This measures the same interval as ExpandAllDiffs, but the result is divided by the number of diffs expanded.
+ FILE_EXPAND_ALL_AVG = 'ExpandAllPerDiff',
+}
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
index cbb3d95..aa28f04 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
@@ -21,8 +21,6 @@
import '../../shared/gr-icons/gr-icons';
import '../gr-permission/gr-permission';
import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {htmlTemplate} from './gr-access-section_html';
import {
AccessPermissions,
@@ -71,9 +69,7 @@
}
@customElement('gr-access-section')
-export class GrAccessSection extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccessSection extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -111,9 +107,8 @@
@property({type: Array})
_permissions?: PermissionArray<EditablePermissionInfo>;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('access-saved', () => this._handleAccessSaved());
}
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
index 4fa84eb..37a2f3e 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
@@ -21,8 +21,6 @@
import '../../shared/gr-list-view/gr-list-view';
import '../../shared/gr-overlay/gr-overlay';
import '../gr-create-group-dialog/gr-create-group-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-admin-group-list_html';
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
@@ -49,9 +47,7 @@
}
@customElement('gr-admin-group-list')
-export class GrAdminGroupList extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrAdminGroupList extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -98,8 +94,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getCreateGroupCapability();
fireTitleChange(this, 'Groups');
this._maybeOpenCreateOverlay(this.params);
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
index 7574f79..91863a9 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
@@ -67,9 +67,7 @@
on-confirm="_handleCreateGroup"
on-cancel="_handleCloseCreate"
>
- <div class="header" slot="header">
- Create Group
- </div>
+ <div class="header" slot="header">Create Group</div>
<div class="main" slot="main">
<gr-create-group-dialog
has-new-group-name="{{_hasNewGroupName}}"
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
index f2b4c89..f8ab519 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
@@ -31,8 +31,6 @@
import '../gr-repo-dashboards/gr-repo-dashboards';
import '../gr-repo-detail-list/gr-repo-detail-list';
import '../gr-repo-list/gr-repo-list';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-admin-view_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -92,9 +90,7 @@
}
@customElement('gr-admin-view')
-export class GrAdminView extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAdminView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -178,8 +174,8 @@
private readonly jsAPI = appContext.jsApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.reload();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
index e813bec..69c218c 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
@@ -20,9 +20,8 @@
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {stubBaseUrl} from '../../../test/test-utils.js';
+import {stubBaseUrl, stubRestApi} from '../../../test/test-utils.js';
import {GerritView} from '../../../services/router/router-model.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-admin-view');
@@ -431,9 +430,7 @@
suite('repos', () => {
setup(() => {
- stub('gr-repo-access', {
- _repoChanged: () => {},
- });
+ stub('gr-repo-access', '_repoChanged').callsFake(() => {});
});
test('repo list', () => {
@@ -500,12 +497,8 @@
suite('groups', () => {
let getGroupConfigStub;
setup(() => {
- stub('gr-group', {
- _loadGroup: () => Promise.resolve({}),
- });
- stub('gr-group-members', {
- _loadGroupDetails: () => {},
- });
+ stub('gr-group', '_loadGroup').callsFake(() => Promise.resolve({}));
+ stub('gr-group-members', '_loadGroupDetails').callsFake(() => {});
getGroupConfigStub = stubRestApi('getGroupConfig');
getGroupConfigStub.returns(Promise.resolve({
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
index 79a3e95..d545b4c 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-delete-item-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -36,9 +34,7 @@
}
@customElement('gr-confirm-delete-item-dialog')
-export class GrConfirmDeleteItemDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmDeleteItemDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
index ce9ac9c..890d345 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
@@ -37,9 +37,7 @@
Do you really want to delete the following
[[_computeItemName(itemType)]]?
</label>
- <div>
- [[item]]
- </div>
+ <div>[[item]]</div>
</div>
</gr-dialog>
`;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
index 2124949..f37e6a3 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
@@ -20,8 +20,6 @@
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-create-change-dialog_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -50,9 +48,7 @@
};
}
@customElement('gr-create-change-dialog')
-export class GrCreateChangeDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateChangeDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -98,8 +94,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
if (!this.repoName) {
return Promise.resolve();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
index 198794e..8a4cbbe 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-create-change-dialog.js';
+import '../../../test/common-test-setup-karma';
+import './gr-create-change-dialog';
import {GrCreateChangeDialog} from './gr-create-change-dialog';
import {BranchName, GitRef, RepoName} from '../../../types/common';
import {InheritedBooleanInfoConfiguredValue} from '../../../constants/constants';
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
index e68f6c9..b4f07cb 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
@@ -17,8 +17,6 @@
import '@polymer/iron-input/iron-input';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-create-group-dialog_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
@@ -28,9 +26,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-create-group-dialog')
-export class GrCreateGroupDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateGroupDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
index 6334670..8875ad4 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-create-pointer-dialog_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
@@ -35,9 +33,7 @@
}
@customElement('gr-create-pointer-dialog')
-export class GrCreatePointerDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreatePointerDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
index f708485..94a4b0a 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
@@ -20,14 +20,17 @@
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-create-repo-dialog_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {page} from '../../../utils/page-wrapper-utils';
import {customElement, observe, property} from '@polymer/decorators';
-import {ProjectInput, RepoName} from '../../../types/common';
+import {
+ BranchName,
+ GroupId,
+ ProjectInput,
+ RepoName,
+} from '../../../types/common';
import {AutocompleteQuery} from '../../shared/gr-autocomplete/gr-autocomplete';
import {appContext} from '../../../services/app-context';
@@ -38,9 +41,7 @@
}
@customElement('gr-create-repo-dialog')
-export class GrCreateRepoDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateRepoDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -53,8 +54,12 @@
create_empty_commit: true,
permissions_only: false,
name: '' as RepoName,
+ branches: [],
};
+ @property({type: String})
+ _defaultBranch?: BranchName;
+
@property({type: Boolean})
_repoCreated = false;
@@ -62,7 +67,7 @@
_repoOwner?: string;
@property({type: String})
- _repoOwnerId?: string;
+ _repoOwnerId?: GroupId;
@property({type: Object})
_query: AutocompleteQuery;
@@ -91,16 +96,9 @@
this.hasNewRepoName = !!name;
}
- @observe('_repoOwnerId')
- _repoOwnerIdUpdate(id?: string) {
- if (id) {
- this.set('_repoConfig.owners', [id]);
- } else {
- this.set('_repoConfig.owners', undefined);
- }
- }
-
handleCreateRepo() {
+ if (this._defaultBranch) this._repoConfig.branches = [this._defaultBranch];
+ if (this._repoOwnerId) this._repoConfig.owners = [this._repoOwnerId];
return this.restApiService
.createRepo(this._repoConfig)
.then(repoRegistered => {
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
index 070ee86..f529ac6 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
@@ -46,6 +46,17 @@
</iron-input>
</section>
<section>
+ <span class="title">Default Branch</span>
+ <iron-input autocomplete="off" bind-value="{{_defaultBranch}}">
+ <input
+ is="iron-input"
+ id="defaultBranchNameInput"
+ autocomplete="off"
+ bind-value="{{_defaultBranch}}"
+ />
+ </iron-input>
+ </section>
+ <section>
<span class="title">Rights inherit from</span>
<span class="value">
<gr-autocomplete
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
index f10141a..e6f9bbe 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
@@ -39,7 +39,6 @@
create_empty_commit: true,
parent: 'All-Project',
permissions_only: false,
- owners: ['testId'],
};
const saveStub = stubRestApi('createRepo').returns(Promise.resolve({}));
@@ -55,10 +54,10 @@
element._repoOwner = 'test';
element._repoOwnerId = 'testId';
+ element._defaultBranch = 'main';
element.$.repoNameInput.bindValue = configInputObj.name;
element.$.rightsInheritFromInput.bindValue = configInputObj.parent;
- element.$.ownerInput.text = configInputObj.owners[0];
element.$.initialCommit.bindValue =
configInputObj.create_empty_commit;
element.$.parentRepo.bindValue =
@@ -69,14 +68,15 @@
assert.deepEqual(element._repoConfig, configInputObj);
element.handleCreateRepo().then(() => {
- assert.isTrue(saveStub.lastCall.calledWithExactly(configInputObj));
+ assert.isTrue(saveStub.lastCall.calledWithExactly(
+ {
+ ...configInputObj,
+ owners: ['testId'],
+ branches: ['main'],
+ }
+ ));
done();
});
});
-
- test('testing observer of _repoOwner', () => {
- element._repoOwnerId = 'test-5';
- assert.deepEqual(element._repoConfig.owners, ['test-5']);
- });
});
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
index 201b340..0bf292d 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../shared/gr-account-link/gr-account-link';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-group-audit-log_html';
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
@@ -39,9 +37,7 @@
const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
@customElement('gr-group-audit-log')
-export class GrGroupAuditLog extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrGroupAuditLog extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -58,8 +54,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
fireTitleChange(this, 'Audit Log');
}
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
index 268112e..fdd5d15 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
@@ -17,8 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-group-audit-log.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-import {addListenerForTest} from '../../../test/test-utils.js';
+import {stubRestApi, addListenerForTest} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-group-audit-log');
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index 54f58c2..bc793fa 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -24,8 +24,6 @@
import '../../shared/gr-button/gr-button';
import '../../shared/gr-overlay/gr-overlay';
import '../gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-group-members_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -63,9 +61,7 @@
};
}
@customElement('gr-group-members')
-export class GrGroupMembers extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrGroupMembers extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -126,8 +122,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadGroupDetails();
fireTitleChange(this, 'Members');
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
index 272cb09..47da237 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
@@ -136,9 +136,7 @@
<tr class="headerRow">
<th class="groupNameHeader">Group Name</th>
<th class="descriptionHeader">Description</th>
- <th class="deleteIncludedHeader">
- Delete Group
- </th>
+ <th class="deleteIncludedHeader">Delete Group</th>
</tr>
</tbody>
<tbody>
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 84daef8..0bb13ba 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -22,8 +22,6 @@
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-group_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -71,9 +69,7 @@
}
@customElement('gr-group')
-export class GrGroup extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrGroup extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -134,8 +130,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadGroup();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
index 4c09e30..0668330 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
@@ -17,8 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-group.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-import {addListenerForTest} from '../../../test/test-utils.js';
+import {stubRestApi, addListenerForTest} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-group');
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
index 85ba052..6f11a33 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
@@ -23,8 +23,6 @@
import '../../shared/gr-button/gr-button';
import '../gr-rule-editor/gr-rule-editor';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-permission_html';
import {
@@ -94,9 +92,7 @@
* @event added-permission-removed
*/
@customElement('gr-permission')
-export class GrPermission extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrPermission extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -145,11 +141,6 @@
constructor() {
super();
this._query = () => this._getGroupSuggestions();
- }
-
- /** @override */
- created() {
- super.created();
this.addEventListener('access-saved', () => this._handleAccessSaved());
}
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
index 6ae982b..3559194 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
@@ -93,7 +93,7 @@
checked="{{permission.value.exclusive}}"
on-change="_handleValueChange"
disabled$="[[!editing]]"
- on-tap="_onTapExclusiveToggle"
+ on-click="_onTapExclusiveToggle"
></paper-toggle-button
>Exclusive
</template>
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
index 1ab32ea..248a0e3 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
@@ -20,8 +20,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-plugin-config-array-editor_html';
import {property, customElement} from '@polymer/decorators';
@@ -38,9 +36,7 @@
}
@customElement('gr-plugin-config-array-editor')
-class GrPluginConfigArrayEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrPluginConfigArrayEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
index f5e9a92..96cae0e 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
@@ -17,8 +17,6 @@
import '../../../styles/gr-table-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-list-view/gr-list-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-plugin-list_html';
import {
@@ -27,8 +25,7 @@
} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {customElement, property} from '@polymer/decorators';
import {PluginInfo} from '../../../types/common';
-import {firePageError} from '../../../utils/event-util';
-import {fireTitleChange} from '../../../utils/event-util';
+import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
@@ -36,9 +33,7 @@
name: string;
}
@customElement('gr-plugin-list')
-export class GrPluginList extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrPluginList extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -80,8 +75,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
fireTitleChange(this, 'Plugins');
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
index 40a1e0a..869a416 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
@@ -72,9 +72,7 @@
extends PermissionRuleInfo,
PropertyTreeNode {}
-export type PermissionAccessSection = PermissionArrayItem<
- EditableAccessSectionInfo
->;
+export type PermissionAccessSection = PermissionArrayItem<EditableAccessSectionInfo>;
export interface NewlyAddedGroupInfo {
name: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 56c5733..80c58ca 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../gr-access-section/gr-access-section';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-access_html';
import {encodeURL, getBaseUrl, singleDecodeURL} from '../../../utils/url-util';
@@ -63,9 +61,7 @@
* @event show-alert
*/
@customElement('gr-repo-access')
-export class GrRepoAccess extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoAccess extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -125,11 +121,6 @@
constructor() {
super();
this._query = () => this._getInheritFromSuggestions();
- }
-
- /** @override */
- created() {
- super.created();
this.addEventListener('access-modified', () =>
this._handleAccessModified()
);
@@ -306,9 +297,18 @@
}
// Restore inheritFrom.
if (this._inheritsFrom) {
- this._inheritsFrom = {...this.originalInheritsFrom};
- this._inheritFromFilter =
- 'name' in this._inheritsFrom ? this._inheritsFrom.name : undefined;
+ // Can't assign this._inheritsFrom = {...this.originalInheritsFrom}
+ // directly, because this._inheritsFrom is declared as
+ // '...|null|undefined` and typescript reports error when trying
+ // to access .name property (because 'name' in null and 'name' in undefined
+ // lead to runtime error)
+ // After migrating to Typescript v4.2 the code below can be rewritten as
+ // const copy = {...this.originalInheritsFrom};
+ const copy: ProjectInfo | {} = this.originalInheritsFrom
+ ? {...this.originalInheritsFrom}
+ : {};
+ this._inheritsFrom = copy;
+ this._inheritFromFilter = 'name' in copy ? copy.name : undefined;
}
if (!this._local) {
return;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index f209729..df78df3 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -23,8 +23,6 @@
import '../../shared/gr-dialog/gr-dialog';
import '../../shared/gr-overlay/gr-overlay';
import '../gr-create-change-dialog/gr-create-change-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-commands_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -61,9 +59,7 @@
}
@customElement('gr-repo-commands')
-export class GrRepoCommands extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoCommands extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -94,8 +90,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadRepo();
fireTitleChange(this, 'Repo Commands');
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
index a77f1ae..f572ac3 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
@@ -76,9 +76,7 @@
on-confirm="_handleCreateChange"
on-cancel="_handleCloseCreateChange"
>
- <div class="header" slot="header">
- Create Change
- </div>
+ <div class="header" slot="header">Create Change</div>
<div class="main" slot="main">
<gr-create-change-dialog
id="createNewChangeModal"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
index 7b3c7fb..815e3ac 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
@@ -17,8 +17,6 @@
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-dashboards_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -34,9 +32,7 @@
}
@customElement('gr-repo-dashboards')
-export class GrRepoDashboards extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoDashboards extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index a486e27..7e6db64 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -28,8 +28,6 @@
import '../gr-create-pointer-dialog/gr-create-pointer-dialog';
import '../gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-detail-list_html';
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
@@ -62,9 +60,7 @@
};
}
@customElement('gr-repo-detail-list')
-export class GrRepoDetailList extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrRepoDetailList extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -122,7 +118,7 @@
_determineIfOwner(repo: RepoName) {
return this.restApiService
.getRepoAccess(repo)
- .then(access => (this._isOwner = !!access && !!access[repo].is_owner));
+ .then(access => (this._isOwner = !!access && !!access[repo]?.is_owner));
}
_paramsChanged(params?: AppElementRepoParams) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
index 4435d3a..2ac32c0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
@@ -91,9 +91,7 @@
<th class$="tagger topHeader [[_hideIfBranch(detailType)]]">
Tagger
</th>
- <th class="repositoryBrowser topHeader">
- Repository Browser
- </th>
+ <th class="repositoryBrowser topHeader">Repository Browser</th>
<th class="delete topHeader"></th>
</tr>
<tr id="loading" class$="loadingMsg [[computeLoadingClass(_loading)]]">
@@ -111,13 +109,9 @@
<td
class$="[[detailType]] revision [[_computeCanEditClass(item.ref, detailType, _isOwner)]]"
>
- <span class="revisionNoEditing">
- [[item.revision]]
- </span>
+ <span class="revisionNoEditing"> [[item.revision]] </span>
<span class$="revisionEdit [[_computeEditingClass(_isEditing)]]">
- <span class="revisionWithEditing">
- [[item.revision]]
- </span>
+ <span class="revisionWithEditing"> [[item.revision]] </span>
<gr-button
link=""
on-click="_handleEditRevision"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
index d6aa0e6..3bc3bef 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
@@ -20,8 +20,6 @@
import '../../shared/gr-list-view/gr-list-view';
import '../../shared/gr-overlay/gr-overlay';
import '../gr-create-repo-dialog/gr-create-repo-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-list_html';
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
@@ -49,9 +47,7 @@
}
@customElement('gr-repo-list')
-export class GrRepoList extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrRepoList extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -91,8 +87,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getCreateRepoCapability();
fireTitleChange(this, 'Repos');
this._maybeOpenCreateOverlay(this.params);
@@ -148,7 +144,9 @@
if (filter !== this._filter || !repos) {
return;
}
- this._repos = repos;
+ this._repos = repos.filter(repo =>
+ repo.name.toLowerCase().includes(filter.toLowerCase())
+ );
this._loading = false;
});
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
index 20c72f9..e1a7f48 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
@@ -104,9 +104,7 @@
on-confirm="_handleCreateRepo"
on-cancel="_handleCloseCreate"
>
- <div class="header" slot="header">
- Create Repository
- </div>
+ <div class="header" slot="header">Create Repository</div>
<div class="main" slot="main">
<gr-create-repo-dialog
has-new-repo-name="{{_hasNewRepoName}}"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
index 4904bf4..c8e058e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
@@ -27,6 +27,7 @@
const repoGenerator = () => {
return {
id: `test${++counter}`,
+ name: `test`,
state: 'ACTIVE',
web_links: [
{
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
index e9a6158..66e4ed6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
@@ -24,8 +24,6 @@
import '../../shared/gr-tooltip-content/gr-tooltip-content';
import '../gr-plugin-config-array-editor/gr-plugin-config-array-editor';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-plugin-config_html';
import {customElement, property} from '@polymer/decorators';
@@ -62,9 +60,7 @@
}
@customElement('gr-repo-plugin-config')
-class GrRepoPluginConfig extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrRepoPluginConfig extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_html.ts
index 3045108..1a7c2a0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_html.ts
@@ -63,7 +63,7 @@
on-change="_handleBooleanChange"
data-option-key$="[[option._key]]"
disabled$="[[_computeDisabled(option.info.editable)]]"
- on-tap="_onTapPluginBoolean"
+ on-click="_onTapPluginBoolean"
></paper-toggle-button>
</template>
<template is="dom-if" if="[[_isList(option.info.type)]]">
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index b6881ff..dc28bcb 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -24,8 +24,6 @@
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
import '../gr-repo-plugin-config/gr-repo-plugin-config';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -83,9 +81,7 @@
};
@customElement('gr-repo')
-export class GrRepo extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRepo extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -144,8 +140,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadRepo();
fireTitleChange(this, `${this.repo}`);
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
index 1ca5636..b88eeaf 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
@@ -50,9 +50,7 @@
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
<div class="info">
- <h1 id="Title" class="heading-1">
- [[repo]]
- </h1>
+ <h1 id="Title" class="heading-1">[[repo]]</h1>
<hr />
<div>
<a href$="[[_computeBrowseUrl(weblinks)]]"
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
index 13d0e50..37e0596 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-rule-editor_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
@@ -102,9 +100,7 @@
}
@customElement('gr-rule-editor')
-export class GrRuleEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRuleEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -140,9 +136,8 @@
@property({type: Object})
_originalRuleValues?: RuleValue;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('access-saved', () => this._handleAccessSaved());
}
@@ -158,8 +153,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
// Check needed for test purposes.
if (!this._originalRuleValues && this.rule) {
// Observer _handleValueChange is called after the ready()
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
index 9cc6357..9c3646a 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
@@ -197,7 +197,7 @@
element._setupValues(element.rule);
flush();
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -306,7 +306,7 @@
flush();
element.rule.value.added = true;
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -371,7 +371,7 @@
element._setupValues(element.rule);
flush();
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -425,7 +425,7 @@
flush();
element.rule.value.added = true;
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -482,7 +482,7 @@
element._setupValues(element.rule);
flush();
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -524,7 +524,7 @@
flush();
element.rule.value.added = true;
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
@@ -571,7 +571,7 @@
element._setupValues(element.rule);
flush();
flush(() => {
- element.attached();
+ element.connectedCallback();
done();
});
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
index 558037d..2869750 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -26,8 +26,6 @@
import '../../../styles/shared-styles';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-list-item_html';
import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
@@ -38,7 +36,7 @@
import {appContext} from '../../../services/app-context';
import {truncatePath} from '../../../utils/path-list-util';
import {changeStatuses} from '../../../utils/change-util';
-import {isServiceUser} from '../../../utils/account-util';
+import {isSelf, isServiceUser} from '../../../utils/account-util';
import {customElement, property} from '@polymer/decorators';
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
import {
@@ -78,9 +76,7 @@
const PRIMARY_REVIEWERS_COUNT = 2;
@customElement('gr-change-list-item')
-export class GrChangeListItem extends ChangeTableMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrChangeListItem extends ChangeTableMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -126,8 +122,8 @@
reporting: ReportingService = appContext.reportingService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
getPluginLoader()
.awaitPluginsLoaded()
.then(() => {
@@ -333,8 +329,8 @@
);
reviewers.sort((r1, r2) => {
if (this.account) {
- if (r1._account_id === this.account._account_id) return -1;
- if (r2._account_id === this.account._account_id) return 1;
+ if (isSelf(r1, this.account)) return -1;
+ if (isSelf(r2, this.account)) return 1;
}
if (this._hasAttention(r1) && !this._hasAttention(r2)) return -1;
if (this._hasAttention(r2) && !this._hasAttention(r1)) return 1;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
index f1e75e4..fac552a 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
@@ -130,21 +130,17 @@
class="cell subject"
hidden$="[[isColumnHidden('Subject', visibleChangeTableColumns)]]"
>
- <div class="container">
- <div class="content">
- <a
- title$="[[change.subject]]"
- href$="[[changeURL]]"
- on-click="_handleChangeClick"
- >
- [[change.subject]]
- </a>
+ <a
+ title$="[[change.subject]]"
+ href$="[[changeURL]]"
+ on-click="_handleChangeClick"
+ >
+ <div class="container">
+ <div class="content">[[change.subject]]</div>
+ <div class="spacer">[[change.subject]]</div>
+ <span> </span>
</div>
- <div class="spacer">
- [[change.subject]]
- </div>
- <span> </span>
- </div>
+ </a>
</td>
<td
class="cell status"
@@ -243,9 +239,7 @@
class="cell branch"
hidden$="[[isColumnHidden('Branch', visibleChangeTableColumns)]]"
>
- <a href$="[[_computeRepoBranchURL(change)]]">
- [[change.branch]]
- </a>
+ <a href$="[[_computeRepoBranchURL(change)]]"> [[change.branch]] </a>
<template is="dom-if" if="[[change.topic]]">
(<a href$="[[_computeTopicURL(change)]]"
><!--
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js
deleted file mode 100644
index acf71c3..0000000
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.js
+++ /dev/null
@@ -1,363 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-change-list-item.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {LabelCategory} from './gr-change-list-item.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-change-list-item');
-
-suite('gr-change-list-item tests', () => {
- let element;
-
- setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('getLoggedIn').returns(Promise.resolve(false));
- element = basicFixture.instantiate();
- });
-
- test('_computeLabelCategory', () => {
- assert.equal(element._computeLabelCategory({labels: {}}),
- LabelCategory.NOT_APPLICABLE);
- assert.equal(element._computeLabelCategory(
- {labels: {}}, 'Verified'), LabelCategory.NOT_APPLICABLE);
- assert.equal(element._computeLabelCategory(
- {labels: {Verified: {approved: true, value: 1}}}, 'Verified'),
- LabelCategory.APPROVED);
- assert.equal(element._computeLabelCategory(
- {labels: {Verified: {rejected: true, value: -1}}}, 'Verified'),
- LabelCategory.REJECTED);
- assert.equal(element._computeLabelCategory(
- {
- labels: {'Code-Review': {approved: true, value: 1}},
- unresolved_comment_count: 1,
- }, 'Code-Review'),
- LabelCategory.UNRESOLVED_COMMENTS);
- assert.equal(element._computeLabelCategory(
- {labels: {'Code-Review': {value: 1}}}, 'Code-Review'),
- LabelCategory.POSITIVE);
- assert.equal(element._computeLabelCategory(
- {labels: {'Code-Review': {value: -1}}}, 'Code-Review'),
- LabelCategory.NEGATIVE);
- assert.equal(element._computeLabelCategory(
- {labels: {'Code-Review': {value: -1}}}, 'Verified'),
- LabelCategory.NOT_APPLICABLE);
- });
-
- test('_computeLabelClass', () => {
- assert.equal(element._computeLabelClass({labels: {}}),
- 'cell label u-gray-background');
- assert.equal(element._computeLabelClass(
- {labels: {}}, 'Verified'), 'cell label u-gray-background');
- assert.equal(element._computeLabelClass(
- {labels: {Verified: {approved: true, value: 1}}}, 'Verified'),
- 'cell label u-green');
- assert.equal(element._computeLabelClass(
- {labels: {Verified: {rejected: true, value: -1}}}, 'Verified'),
- 'cell label u-red');
- assert.equal(element._computeLabelClass(
- {labels: {'Code-Review': {value: 1}}}, 'Code-Review'),
- 'cell label u-green u-monospace');
- assert.equal(element._computeLabelClass(
- {labels: {'Code-Review': {value: -1}}}, 'Code-Review'),
- 'cell label u-monospace u-red');
- assert.equal(element._computeLabelClass(
- {labels: {'Code-Review': {value: -1}}}, 'Verified'),
- 'cell label u-gray-background');
- });
-
- test('_computeLabelTitle', () => {
- assert.equal(element._computeLabelTitle({labels: {}}, 'Verified'),
- 'Label not applicable');
- assert.equal(element._computeLabelTitle(
- {labels: {Verified: {approved: {name: 'Diffy'}}}}, 'Verified'),
- 'Verified by Diffy');
- assert.equal(element._computeLabelTitle(
- {labels: {Verified: {approved: {name: 'Diffy'}}}}, 'Code-Review'),
- 'Label not applicable');
- assert.equal(element._computeLabelTitle(
- {labels: {Verified: {rejected: {name: 'Diffy'}}}}, 'Verified'),
- 'Verified by Diffy');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {disliked: {name: 'Diffy'}, value: -1}}},
- 'Code-Review'), 'Code-Review by Diffy');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {recommended: {name: 'Diffy'}, value: 1}}},
- 'Code-Review'), 'Code-Review by Diffy');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {recommended: {name: 'Diffy'},
- rejected: {name: 'Admin'}}}}, 'Code-Review'),
- 'Code-Review by Admin');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {approved: {name: 'Diffy'},
- rejected: {name: 'Admin'}}}}, 'Code-Review'),
- 'Code-Review by Admin');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {recommended: {name: 'Diffy'},
- disliked: {name: 'Admin'}, value: -1}}}, 'Code-Review'),
- 'Code-Review by Admin');
- assert.equal(element._computeLabelTitle(
- {labels: {'Code-Review': {approved: {name: 'Diffy'},
- disliked: {name: 'Admin'}, value: -1}}}, 'Code-Review'),
- 'Code-Review by Diffy');
- assert.equal(element._computeLabelTitle(
- {
- labels: {'Code-Review': {approved: true, value: 1}},
- unresolved_comment_count: 1,
- }, 'Code-Review'),
- '1 unresolved comment');
- assert.equal(element._computeLabelTitle(
- {
- labels: {'Code-Review': {approved: {name: 'Diffy'}, value: 1}},
- unresolved_comment_count: 1,
- }, 'Code-Review'),
- '1 unresolved comment,\nCode-Review by Diffy');
- assert.equal(element._computeLabelTitle(
- {
- labels: {'Code-Review': {approved: true, value: 1}},
- unresolved_comment_count: 2,
- }, 'Code-Review'),
- '2 unresolved comments');
- });
-
- test('_computeLabelIcon', () => {
- assert.equal(element._computeLabelIcon({labels: {}}), '');
- assert.equal(element._computeLabelIcon(
- {labels: {Verified: {approved: true, value: 1}}}, 'Verified'),
- 'gr-icons:check');
- assert.equal(element._computeLabelIcon(
- {
- labels: {'Code-Review': {approved: true, value: 1}},
- unresolved_comment_count: 1,
- }, 'Code-Review'),
- 'gr-icons:comment');
- });
-
- test('_computeLabelValue', () => {
- assert.equal(element._computeLabelValue({labels: {}}), '');
- assert.equal(element._computeLabelValue({labels: {}}, 'Verified'), '');
- assert.equal(element._computeLabelValue(
- {labels: {Verified: {approved: true, value: 1}}}, 'Verified'), '✓');
- assert.equal(element._computeLabelValue(
- {labels: {Verified: {value: 1}}}, 'Verified'), '+1');
- assert.equal(element._computeLabelValue(
- {labels: {Verified: {value: -1}}}, 'Verified'), '-1');
- assert.equal(element._computeLabelValue(
- {labels: {Verified: {approved: true}}}, 'Verified'), '✓');
- assert.equal(element._computeLabelValue(
- {labels: {Verified: {rejected: true}}}, 'Verified'), '✕');
- });
-
- test('no hidden columns', () => {
- element.visibleChangeTableColumns = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Reviewers',
- 'Comments',
- 'Repo',
- 'Branch',
- 'Updated',
- 'Size',
- ];
-
- flush();
-
- for (const column of element.columnNames) {
- const elementClass = '.' + column.toLowerCase();
- assert.isOk(element.shadowRoot
- .querySelector(elementClass),
- `Expect ${elementClass} element to be found`);
- assert.isFalse(element.shadowRoot
- .querySelector(elementClass).hidden);
- }
- });
-
- test('repo column hidden', () => {
- element.visibleChangeTableColumns = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Reviewers',
- 'Comments',
- 'Branch',
- 'Updated',
- 'Size',
- ];
-
- flush();
-
- for (const column of element.columnNames) {
- const elementClass = '.' + column.toLowerCase();
- if (column === 'Repo') {
- assert.isTrue(element.shadowRoot
- .querySelector(elementClass).hidden);
- } else {
- assert.isFalse(element.shadowRoot
- .querySelector(elementClass).hidden);
- }
- }
- });
-
- function checkComputeReviewers(
- userId, reviewerIds, reviewerNames, attSetIds, expected) {
- element.account = userId ? {_account_id: userId} : null;
- element.change = {
- owner: {
- _account_id: 99,
- },
- reviewers: {
- REVIEWER: [],
- },
- attention_set: {},
- };
- for (let i = 0; i < reviewerIds.length; i++) {
- element.change.reviewers.REVIEWER.push({
- _account_id: reviewerIds[i],
- name: reviewerNames[i],
- });
- }
- attSetIds.forEach(id => element.change.attention_set[id] = {});
-
- const actual = element._computeReviewers(element.change)
- .map(r => r._account_id);
- assert.deepEqual(actual, expected);
- }
-
- test('compute reviewers', () => {
- checkComputeReviewers(null, [], [], [], []);
- checkComputeReviewers(1, [], [], [], []);
- checkComputeReviewers(1, [2], ['a'], [], [2]);
- checkComputeReviewers(1, [2, 3], [undefined, 'a'], [], [2, 3]);
- checkComputeReviewers(1, [2, 3], ['a', undefined], [], [3, 2]);
- checkComputeReviewers(1, [99], ['owner'], [], []);
- checkComputeReviewers(
- 1, [2, 3, 4, 5], ['b', 'a', 'd', 'c'], [3, 4], [3, 4, 2, 5]);
- checkComputeReviewers(
- 1, [2, 3, 1, 4, 5], ['b', 'a', 'x', 'd', 'c'], [3, 4], [1, 3, 4, 2, 5]);
- });
-
- test('random column does not exist', () => {
- element.visibleChangeTableColumns = [
- 'Bad',
- ];
-
- flush();
- const elementClass = '.bad';
- assert.isNotOk(element.shadowRoot
- .querySelector(elementClass));
- });
-
- test('assignee only displayed if there is one', () => {
- element.change = {};
- flush();
- assert.isNotOk(element.shadowRoot
- .querySelector('.assignee gr-account-link'));
- assert.equal(element.shadowRoot
- .querySelector('.assignee').textContent.trim(), '--');
- element.change = {
- assignee: {
- name: 'test',
- status: 'test',
- },
- };
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('.assignee gr-account-link'));
- });
-
- test('TShirt sizing tooltip', () => {
- assert.equal(element._computeSizeTooltip({
- insertions: 'foo',
- deletions: 'bar',
- }), 'Size unknown');
- assert.equal(element._computeSizeTooltip({
- insertions: 0,
- deletions: 0,
- }), 'Size unknown');
- assert.equal(element._computeSizeTooltip({
- insertions: 1,
- deletions: 2,
- }), 'added 1, removed 2 lines');
- });
-
- test('TShirt sizing', () => {
- assert.equal(element._computeChangeSize({
- insertions: 'foo',
- deletions: 'bar',
- }), null);
- assert.equal(element._computeChangeSize({
- insertions: 1,
- deletions: 1,
- }), 'XS');
- assert.equal(element._computeChangeSize({
- insertions: 9,
- deletions: 1,
- }), 'S');
- assert.equal(element._computeChangeSize({
- insertions: 10,
- deletions: 200,
- }), 'M');
- assert.equal(element._computeChangeSize({
- insertions: 99,
- deletions: 900,
- }), 'L');
- assert.equal(element._computeChangeSize({
- insertions: 99,
- deletions: 999,
- }), 'XL');
- });
-
- test('change params passed to gr-navigation', () => {
- sinon.stub(GerritNav);
- const change = {
- internalHost: 'test-host',
- project: 'test-repo',
- topic: 'test-topic',
- branch: 'test-branch',
- };
- element.change = change;
- flush();
-
- assert.deepEqual(GerritNav.getUrlForChange.lastCall.args, [change]);
- assert.deepEqual(GerritNav.getUrlForProjectChanges.lastCall.args,
- [change.project, true, change.internalHost]);
- assert.deepEqual(GerritNav.getUrlForBranch.lastCall.args,
- [change.branch, change.project, undefined, change.internalHost]);
- assert.deepEqual(GerritNav.getUrlForTopic.lastCall.args,
- [change.topic, change.internalHost]);
- });
-
- test('_computeRepoDisplay', () => {
- const change = {
- project: 'a/test/repo',
- internalHost: 'host',
- };
- assert.equal(element._computeRepoDisplay(change), 'host/a/test/repo');
- assert.equal(element._computeRepoDisplay(change, true),
- 'host/…/test/repo');
- delete change.internalHost;
- assert.equal(element._computeRepoDisplay(change), 'a/test/repo');
- assert.equal(element._computeRepoDisplay(change, true),
- '…/test/repo');
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts
new file mode 100644
index 0000000..ac0b929
--- /dev/null
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts
@@ -0,0 +1,577 @@
+/**
+ * @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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import {
+ createAccountWithId,
+ createChange,
+} from '../../../test/test-data-generators';
+import {query, queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {
+ AccountId,
+ BranchName,
+ ChangeInfo,
+ RepoName,
+ TopicName,
+} from '../../../types/common';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import './gr-change-list-item';
+import {GrChangeListItem, LabelCategory} from './gr-change-list-item';
+
+const basicFixture = fixtureFromElement('gr-change-list-item');
+
+suite('gr-change-list-item tests', () => {
+ const account = createAccountWithId();
+ const change: ChangeInfo = {
+ ...createChange(),
+ internalHost: 'host',
+ project: 'a/test/repo' as RepoName,
+ topic: 'test-topic' as TopicName,
+ branch: 'test-branch' as BranchName,
+ };
+
+ let element: GrChangeListItem;
+
+ setup(() => {
+ stubRestApi('getLoggedIn').returns(Promise.resolve(false));
+ element = basicFixture.instantiate();
+ });
+
+ test('_computeLabelCategory', () => {
+ assert.equal(
+ element._computeLabelCategory({...change, labels: {}}, 'Verified'),
+ LabelCategory.NOT_APPLICABLE
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {...change, labels: {Verified: {approved: account, value: 1}}},
+ 'Verified'
+ ),
+ LabelCategory.APPROVED
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {...change, labels: {Verified: {rejected: account, value: -1}}},
+ 'Verified'
+ ),
+ LabelCategory.REJECTED
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {
+ ...change,
+ labels: {'Code-Review': {approved: account, value: 1}},
+ unresolved_comment_count: 1,
+ },
+ 'Code-Review'
+ ),
+ LabelCategory.UNRESOLVED_COMMENTS
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {...change, labels: {'Code-Review': {value: 1}}},
+ 'Code-Review'
+ ),
+ LabelCategory.POSITIVE
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {...change, labels: {'Code-Review': {value: -1}}},
+ 'Code-Review'
+ ),
+ LabelCategory.NEGATIVE
+ );
+ assert.equal(
+ element._computeLabelCategory(
+ {...change, labels: {'Code-Review': {value: -1}}},
+ 'Verified'
+ ),
+ LabelCategory.NOT_APPLICABLE
+ );
+ });
+
+ test('_computeLabelClass', () => {
+ assert.equal(
+ element._computeLabelClass({...change, labels: {}}, 'Verified'),
+ 'cell label u-gray-background'
+ );
+ assert.equal(
+ element._computeLabelClass(
+ {...change, labels: {Verified: {approved: account, value: 1}}},
+ 'Verified'
+ ),
+ 'cell label u-green'
+ );
+ assert.equal(
+ element._computeLabelClass(
+ {...change, labels: {Verified: {rejected: account, value: -1}}},
+ 'Verified'
+ ),
+ 'cell label u-red'
+ );
+ assert.equal(
+ element._computeLabelClass(
+ {...change, labels: {'Code-Review': {value: 1}}},
+ 'Code-Review'
+ ),
+ 'cell label u-green u-monospace'
+ );
+ assert.equal(
+ element._computeLabelClass(
+ {...change, labels: {'Code-Review': {value: -1}}},
+ 'Code-Review'
+ ),
+ 'cell label u-monospace u-red'
+ );
+ assert.equal(
+ element._computeLabelClass(
+ {...change, labels: {'Code-Review': {value: -1}}},
+ 'Verified'
+ ),
+ 'cell label u-gray-background'
+ );
+ });
+
+ test('_computeLabelTitle', () => {
+ assert.equal(
+ element._computeLabelTitle({...change, labels: {}}, 'Verified'),
+ 'Label not applicable'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {...change, labels: {Verified: {approved: {name: 'Diffy'}}}},
+ 'Verified'
+ ),
+ 'Verified by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {...change, labels: {Verified: {approved: {name: 'Diffy'}}}},
+ 'Code-Review'
+ ),
+ 'Label not applicable'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {...change, labels: {Verified: {rejected: {name: 'Diffy'}}}},
+ 'Verified'
+ ),
+ 'Verified by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {'Code-Review': {disliked: {name: 'Diffy'}, value: -1}},
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {'Code-Review': {recommended: {name: 'Diffy'}, value: 1}},
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {
+ 'Code-Review': {
+ recommended: {name: 'Diffy'},
+ rejected: {name: 'Admin'},
+ },
+ },
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Admin'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {
+ 'Code-Review': {
+ approved: {name: 'Diffy'},
+ rejected: {name: 'Admin'},
+ },
+ },
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Admin'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {
+ 'Code-Review': {
+ recommended: {name: 'Diffy'},
+ disliked: {name: 'Admin'},
+ value: -1,
+ },
+ },
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Admin'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {
+ 'Code-Review': {
+ approved: {name: 'Diffy'},
+ disliked: {name: 'Admin'},
+ value: -1,
+ },
+ },
+ },
+ 'Code-Review'
+ ),
+ 'Code-Review by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {'Code-Review': {approved: account, value: 1}},
+ unresolved_comment_count: 1,
+ },
+ 'Code-Review'
+ ),
+ '1 unresolved comment'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {'Code-Review': {approved: {name: 'Diffy'}, value: 1}},
+ unresolved_comment_count: 1,
+ },
+ 'Code-Review'
+ ),
+ '1 unresolved comment,\nCode-Review by Diffy'
+ );
+ assert.equal(
+ element._computeLabelTitle(
+ {
+ ...change,
+ labels: {'Code-Review': {approved: account, value: 1}},
+ unresolved_comment_count: 2,
+ },
+ 'Code-Review'
+ ),
+ '2 unresolved comments'
+ );
+ });
+
+ test('_computeLabelIcon', () => {
+ assert.equal(
+ element._computeLabelIcon({...change, labels: {}}, 'missingLabel'),
+ ''
+ );
+ assert.equal(
+ element._computeLabelIcon(
+ {...change, labels: {Verified: {approved: account, value: 1}}},
+ 'Verified'
+ ),
+ 'gr-icons:check'
+ );
+ assert.equal(
+ element._computeLabelIcon(
+ {
+ ...change,
+ labels: {'Code-Review': {approved: account, value: 1}},
+ unresolved_comment_count: 1,
+ },
+ 'Code-Review'
+ ),
+ 'gr-icons:comment'
+ );
+ });
+
+ test('_computeLabelValue', () => {
+ assert.equal(
+ element._computeLabelValue({...change, labels: {}}, 'Verified'),
+ ''
+ );
+ assert.equal(
+ element._computeLabelValue(
+ {...change, labels: {Verified: {approved: account, value: 1}}},
+ 'Verified'
+ ),
+ '✓'
+ );
+ assert.equal(
+ element._computeLabelValue(
+ {...change, labels: {Verified: {value: 1}}},
+ 'Verified'
+ ),
+ '+1'
+ );
+ assert.equal(
+ element._computeLabelValue(
+ {...change, labels: {Verified: {value: -1}}},
+ 'Verified'
+ ),
+ '-1'
+ );
+ assert.equal(
+ element._computeLabelValue(
+ {...change, labels: {Verified: {approved: account}}},
+ 'Verified'
+ ),
+ '✓'
+ );
+ assert.equal(
+ element._computeLabelValue(
+ {...change, labels: {Verified: {rejected: account}}},
+ 'Verified'
+ ),
+ '✕'
+ );
+ });
+
+ test('no hidden columns', async () => {
+ element.visibleChangeTableColumns = [
+ 'Subject',
+ 'Status',
+ 'Owner',
+ 'Assignee',
+ 'Reviewers',
+ 'Comments',
+ 'Repo',
+ 'Branch',
+ 'Updated',
+ 'Size',
+ ];
+
+ await flush();
+
+ for (const column of element.columnNames) {
+ const elementClass = '.' + column.toLowerCase();
+ assert.isFalse(
+ queryAndAssert(element, elementClass).hasAttribute('hidden')
+ );
+ }
+ });
+
+ test('repo column hidden', async () => {
+ element.visibleChangeTableColumns = [
+ 'Subject',
+ 'Status',
+ 'Owner',
+ 'Assignee',
+ 'Reviewers',
+ 'Comments',
+ 'Branch',
+ 'Updated',
+ 'Size',
+ ];
+
+ await flush();
+
+ for (const column of element.columnNames) {
+ const elementClass = '.' + column.toLowerCase();
+ if (column === 'Repo') {
+ assert.isTrue(
+ queryAndAssert(element, elementClass).hasAttribute('hidden')
+ );
+ } else {
+ assert.isFalse(
+ queryAndAssert(element, elementClass).hasAttribute('hidden')
+ );
+ }
+ }
+ });
+
+ function checkComputeReviewers(
+ userId: number | undefined,
+ reviewerIds: number[],
+ reviewerNames: (string | undefined)[],
+ attSetIds: number[],
+ expected: number[]
+ ) {
+ element.account = userId ? {_account_id: userId as AccountId} : null;
+ element.change = {
+ ...change,
+ owner: {
+ _account_id: 99 as AccountId,
+ },
+ reviewers: {
+ REVIEWER: [],
+ },
+ attention_set: {},
+ };
+ for (let i = 0; i < reviewerIds.length; i++) {
+ element.change!.reviewers.REVIEWER!.push({
+ _account_id: reviewerIds[i] as AccountId,
+ name: reviewerNames[i],
+ });
+ }
+ attSetIds.forEach(id => (element.change!.attention_set![id] = {account}));
+
+ const actual = element
+ ._computeReviewers(element.change)
+ .map(r => r._account_id);
+ assert.deepEqual(actual, expected as AccountId[]);
+ }
+
+ test('compute reviewers', () => {
+ checkComputeReviewers(undefined, [], [], [], []);
+ checkComputeReviewers(1, [], [], [], []);
+ checkComputeReviewers(1, [2], ['a'], [], [2]);
+ checkComputeReviewers(1, [2, 3], [undefined, 'a'], [], [2, 3]);
+ checkComputeReviewers(1, [2, 3], ['a', undefined], [], [3, 2]);
+ checkComputeReviewers(1, [99], ['owner'], [], []);
+ checkComputeReviewers(
+ 1,
+ [2, 3, 4, 5],
+ ['b', 'a', 'd', 'c'],
+ [3, 4],
+ [3, 4, 2, 5]
+ );
+ checkComputeReviewers(
+ 1,
+ [2, 3, 1, 4, 5],
+ ['b', 'a', 'x', 'd', 'c'],
+ [3, 4],
+ [1, 3, 4, 2, 5]
+ );
+ });
+
+ test('random column does not exist', async () => {
+ element.visibleChangeTableColumns = ['Bad'];
+
+ await flush();
+ const elementClass = '.bad';
+ assert.isNotOk(query(element, elementClass));
+ });
+
+ test('assignee only displayed if there is one', async () => {
+ element.change = change;
+ await flush();
+ assert.isNotOk(query(element, '.assignee gr-account-link'));
+ assert.equal(
+ queryAndAssert(element, '.assignee').textContent!.trim(),
+ '--'
+ );
+ element.change = {
+ ...change,
+ assignee: {
+ name: 'test',
+ status: 'test',
+ },
+ };
+ await flush();
+ queryAndAssert(element, '.assignee gr-account-link');
+ });
+
+ test('TShirt sizing tooltip', () => {
+ assert.equal(
+ element._computeSizeTooltip({
+ ...change,
+ insertions: NaN,
+ deletions: NaN,
+ }),
+ 'Size unknown'
+ );
+ assert.equal(
+ element._computeSizeTooltip({...change, insertions: 0, deletions: 0}),
+ 'Size unknown'
+ );
+ assert.equal(
+ element._computeSizeTooltip({...change, insertions: 1, deletions: 2}),
+ 'added 1, removed 2 lines'
+ );
+ });
+
+ test('TShirt sizing', () => {
+ assert.equal(
+ element._computeChangeSize({
+ ...change,
+ insertions: NaN,
+ deletions: NaN,
+ }),
+ null
+ );
+ assert.equal(
+ element._computeChangeSize({...change, insertions: 1, deletions: 1}),
+ 'XS'
+ );
+ assert.equal(
+ element._computeChangeSize({...change, insertions: 9, deletions: 1}),
+ 'S'
+ );
+ assert.equal(
+ element._computeChangeSize({...change, insertions: 10, deletions: 200}),
+ 'M'
+ );
+ assert.equal(
+ element._computeChangeSize({...change, insertions: 99, deletions: 900}),
+ 'L'
+ );
+ assert.equal(
+ element._computeChangeSize({...change, insertions: 99, deletions: 999}),
+ 'XL'
+ );
+ });
+
+ test('change params passed to gr-navigation', async () => {
+ const navStub = sinon.stub(GerritNav);
+ element.change = change;
+ await flush();
+
+ assert.deepEqual(navStub.getUrlForChange.lastCall.args, [change]);
+ assert.deepEqual(navStub.getUrlForProjectChanges.lastCall.args, [
+ change.project,
+ true,
+ change.internalHost,
+ ]);
+ assert.deepEqual(navStub.getUrlForBranch.lastCall.args, [
+ change.branch,
+ change.project,
+ undefined,
+ change.internalHost,
+ ]);
+ assert.deepEqual(navStub.getUrlForTopic.lastCall.args, [
+ change.topic,
+ change.internalHost,
+ ]);
+ });
+
+ test('_computeRepoDisplay', () => {
+ assert.equal(
+ element._computeRepoDisplay(change, false),
+ 'host/a/test/repo'
+ );
+ assert.equal(element._computeRepoDisplay(change, true), 'host/…/test/repo');
+ delete change.internalHost;
+ assert.equal(element._computeRepoDisplay(change, false), 'a/test/repo');
+ assert.equal(element._computeRepoDisplay(change, true), '…/test/repo');
+ });
+});
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
index 42741fa..8ce00f2 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
@@ -20,8 +20,6 @@
import '../gr-repo-header/gr-repo-header';
import '../gr-user-header/gr-user-header';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-list-view_html';
import {page} from '../../../utils/page-wrapper-utils';
@@ -62,9 +60,7 @@
}
@customElement('gr-change-list-view')
-export class GrChangeListView extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrChangeListView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -113,16 +109,15 @@
private readonly restApiService = appContext.restApiService;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('next-page', () => this._handleNextPage());
this.addEventListener('previous-page', () => this._handlePreviousPage());
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadPreferences();
}
@@ -144,7 +139,7 @@
// NOTE: This method may be called before attachment. Fire title-change
// in an async so that attachment to the DOM can take place first.
- this.async(() => fireTitleChange(this, this._query));
+ setTimeout(() => fireTitleChange(this, this._query));
this.restApiService
.getPreferences()
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index f26cd46..62cfcb4 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -21,8 +21,6 @@
import '../../../styles/shared-styles';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-list_html';
import {appContext} from '../../../services/app-context';
@@ -56,6 +54,7 @@
import {CustomKeyboardEvent} from '../../../types/events';
import {fireEvent} from '../../../utils/event-util';
import {windowLocationReload} from '../../../utils/dom-util';
+import {ScrollMode} from '../../../constants/constants';
const NUMBER_FIXED_COLUMNS = 3;
const CLOSED_STATUS = ['MERGED', 'ABANDONED'];
@@ -68,15 +67,11 @@
results: ChangeInfo[];
}
export interface GrChangeList {
- $: {
- cursor: GrCursorManager;
- };
+ $: {};
}
@customElement('gr-change-list')
export class GrChangeList extends ChangeTableMixin(
- KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
- )
+ KeyboardShortcutMixin(PolymerElement)
) {
static get template() {
return htmlTemplate;
@@ -141,6 +136,9 @@
@property({type: Object})
preferences?: PreferencesInput;
+ @property({type: Boolean})
+ isCursorMoving = false;
+
@property({type: Object})
_config?: ServerInfo;
@@ -161,9 +159,12 @@
};
}
- /** @override */
- created() {
- super.created();
+ private cursor = new GrCursorManager();
+
+ constructor() {
+ super();
+ this.cursor.scrollMode = ScrollMode.KEEP_VISIBLE;
+ this.cursor.focusOnMove = true;
this.addEventListener('keydown', e => this._scopedKeydownHandler(e));
}
@@ -176,8 +177,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
getPluginLoader()
.awaitPluginsLoaded()
.then(() => {
@@ -187,6 +188,12 @@
});
}
+ /** @override */
+ disconnectedCallback() {
+ this.cursor.unsetCursor();
+ super.disconnectedCallback();
+ }
+
/**
* Iron-a11y-keys-behavior catches keyboard events globally. Some keyboard
* events must be scoped to a component level (e.g. `enter`) in order to not
@@ -352,7 +359,13 @@
return idx === selectedIndex;
}
- _computeTabIndex(sectionIndex: number, index: number, selectedIndex: number) {
+ _computeTabIndex(
+ sectionIndex: number,
+ index: number,
+ selectedIndex: number,
+ isCursorMoving: boolean
+ ) {
+ if (isCursorMoving) return 0;
return this._computeItemSelected(sectionIndex, index, selectedIndex)
? 0
: undefined;
@@ -395,8 +408,10 @@
}
e.preventDefault();
- this.$.cursor.next();
- this.selectedIndex = this.$.cursor.index;
+ this.isCursorMoving = true;
+ this.cursor.next();
+ this.isCursorMoving = false;
+ this.selectedIndex = this.cursor.index;
}
_prevChange(e: CustomKeyboardEvent) {
@@ -405,8 +420,10 @@
}
e.preventDefault();
- this.$.cursor.previous();
- this.selectedIndex = this.$.cursor.index;
+ this.isCursorMoving = true;
+ this.cursor.previous();
+ this.isCursorMoving = false;
+ this.selectedIndex = this.cursor.index;
}
_openChange(e: CustomKeyboardEvent) {
@@ -519,10 +536,9 @@
_sectionsChanged() {
// Flush DOM operations so that the list item elements will be loaded.
afterNextRender(this, () => {
- this.$.cursor.stops = this._getListItems();
- this.$.cursor.moveToStart();
- if (this.selectedIndex)
- this.$.cursor.setCursorAtIndex(this.selectedIndex);
+ this.cursor.stops = this._getListItems();
+ this.cursor.moveToStart();
+ if (this.selectedIndex) this.cursor.setCursorAtIndex(this.selectedIndex);
});
}
@@ -535,6 +551,11 @@
_isEmpty(section: DashboardSection) {
return !section.results?.length;
}
+
+ _computeAriaLabel(change?: ChangeInfo, sectionName?: string) {
+ if (!change) return '';
+ return change.subject + (sectionName ? `, section: ${sectionName}` : '');
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
index 0313e0b..317d27f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
@@ -121,9 +121,7 @@
items="[[_computeColumns(changeSection, visibleChangeTableColumns)]]"
as="item"
>
- <td class$="[[_lowerCase(item)]]">
- [[item]]
- </td>
+ <td class$="[[_lowerCase(item)]]">[[item]]</td>
</template>
<template is="dom-repeat" items="[[labelNames]]" as="labelName">
<td class="label" title$="[[labelName]]">
@@ -154,16 +152,12 @@
visible-change-table-columns="[[_computeColumns(changeSection, visibleChangeTableColumns)]]"
show-number="[[showNumber]]"
show-star="[[showStar]]"
- tabindex$="[[_computeTabIndex(sectionIndex, index, selectedIndex)]]"
+ tabindex$="[[_computeTabIndex(sectionIndex, index, selectedIndex, isCursorMoving)]]"
label-names="[[labelNames]]"
+ aria-label$="[[_computeAriaLabel(change, changeSection.name)]]"
></gr-change-list-item>
</template>
</tbody>
</template>
</table>
- <gr-cursor-manager
- id="cursor"
- scroll-mode="keep-visible"
- focus-on-move=""
- ></gr-cursor-manager>
`;
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
index f320296..0e2668d 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
@@ -18,8 +18,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-icons/gr-icons';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement} from '@polymer/decorators';
import {htmlTemplate} from './gr-create-change-help_html';
@@ -32,9 +30,7 @@
}
@customElement('gr-create-change-help')
-class GrCreateChangeHelp extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrCreateChangeHelp extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
index add7ca5..95a67af 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
@@ -64,9 +64,7 @@
<div id="circle">
<iron-icon id="icon" icon="gr-icons:zeroState"></iron-icon>
</div>
- <p>
- No outgoing changes yet
- </p>
+ <p>No outgoing changes yet</p>
</div>
<div id="help">
<h2 class="heading-3">Push your first change for code review</h2>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
index 1ee8cb5..f2f767a 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-overlay/gr-overlay';
import '../../shared/gr-shell-command/gr-shell-command';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
import {htmlTemplate} from './gr-create-commands-dialog_html';
@@ -44,9 +42,7 @@
}
@customElement('gr-create-commands-dialog')
-export class GrCreateCommandsDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateCommandsDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
index 9031738..d2f35d6 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
@@ -37,26 +37,18 @@
confirm-on-enter=""
on-confirm="_handleClose"
>
- <div class="header" slot="header">
- Create change commands
- </div>
+ <div class="header" slot="header">Create change commands</div>
<div class="main" slot="main">
<ol>
<li>
- <p>
- Make the changes to the files on your machine
- </p>
+ <p>Make the changes to the files on your machine</p>
</li>
<li>
- <p>
- If you are making a new commit use
- </p>
+ <p>If you are making a new commit use</p>
<gr-shell-command
command="[[_createNewCommitCommand]]"
></gr-shell-command>
- <p>
- Or to amend an existing commit use
- </p>
+ <p>Or to amend an existing commit use</p>
<gr-shell-command
command="[[_amendExistingCommitCommand]]"
></gr-shell-command>
@@ -66,9 +58,7 @@
</p>
</li>
<li>
- <p>
- Push the change for code review
- </p>
+ <p>Push the change for code review</p>
<gr-shell-command command="[[_pushCommand]]"></gr-shell-command>
</li>
<li>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
index e53f68b..ff9666b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-dialog/gr-dialog';
import '../../shared/gr-overlay/gr-overlay';
import '../../shared/gr-repo-branch-picker/gr-repo-branch-picker';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-create-destination-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -44,9 +42,7 @@
}
@customElement('gr-create-destination-dialog')
-export class GrCreateDestinationDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCreateDestinationDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
index 9155d9a..0aed75b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
@@ -25,17 +25,13 @@
on-cancel="_handleClose"
disabled="[[!_repoAndBranchSelected]]"
>
- <div class="header" slot="header">
- Create change
- </div>
+ <div class="header" slot="header">Create change</div>
<div class="main" slot="main">
<gr-repo-branch-picker
repo="{{_repo}}"
branch="{{_branch}}"
></gr-repo-branch-picker>
- <p>
- If you haven't done so, you will need to clone the repository.
- </p>
+ <p>If you haven't done so, you will need to clone the repository.</p>
</div>
</gr-dialog>
</gr-overlay>
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
index a34bd63..f9dee5f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
@@ -23,8 +23,6 @@
import '../gr-create-change-help/gr-create-change-help';
import '../gr-create-destination-dialog/gr-create-destination-dialog';
import '../gr-user-header/gr-user-header';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dashboard-view_html';
import {
@@ -79,9 +77,7 @@
}
@customElement('gr-dashboard-view')
-export class GrDashboardView extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDashboardView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -130,8 +126,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadPreferences();
this.addEventListener('reload', e => {
e.stopPropagation();
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
index 730797c..fd23970 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
@@ -92,9 +92,7 @@
on-create-tap="_handleCreateChangeTap"
></gr-create-change-help>
</template>
- <template is="dom-if" if="[[!_showNewUserHelp]]">
- No changes
- </template>
+ <template is="dom-if" if="[[!_showNewUserHelp]]"> No changes </template>
</div>
<div id="emptyYourTurn" slot="empty-your-turn">
<span>No changes need your attention 🎉</span>
@@ -108,9 +106,7 @@
on-confirm="_handleConfirmDelete"
on-cancel="_closeConfirmDeleteOverlay"
>
- <div class="header" slot="header">
- Delete comments
- </div>
+ <div class="header" slot="header">Delete comments</div>
<div class="main" slot="main">
Are you sure you want to delete all your draft comments in closed
changes? This action cannot be undone.
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
index a5de72b..165306e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
@@ -17,13 +17,12 @@
import '../../../test/common-test-setup-karma.js';
import './gr-dashboard-view.js';
-import {isHidden} from '../../../test/test-utils.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {GerritView} from '../../../services/router/router-model.js';
import {changeIsOpen} from '../../../utils/change-util.js';
import {ChangeStatus} from '../../../constants/constants.js';
import {createAccountWithId} from '../../../test/test-data-generators.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {addListenerForTest, stubRestApi, isHidden} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-dashboard-view');
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
index 35a2a7f..6d7b5b1 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
@@ -18,19 +18,16 @@
import '../../../styles/dashboard-header-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-date-formatter/gr-date-formatter';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-header_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property} from '@polymer/decorators';
import {RepoName} from '../../../types/common';
+import {WebLinkInfo} from '../../../types/diff';
+import {appContext} from '../../../services/app-context';
-/** @extends PolymerElement */
@customElement('gr-repo-header')
-class GrRepoHeader extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrRepoHeader extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -41,12 +38,23 @@
@property({type: String})
_repoUrl: string | null = null;
+ @property({type: Array})
+ _webLinks: WebLinkInfo[] = [];
+
+ private readonly restApiService = appContext.restApiService;
+
_repoChanged(repoName: RepoName) {
if (!repoName) {
this._repoUrl = null;
return;
}
+
this._repoUrl = GerritNav.getUrlForRepo(repoName);
+
+ this.restApiService.getRepo(repoName).then(repo => {
+ if (!repo?.web_links) return;
+ this._webLinks = repo.web_links;
+ });
}
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
index 2dd2913..0dbec1c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
@@ -18,16 +18,28 @@
export const htmlTemplate = html`
<style include="shared-styles">
+ .browse {
+ display: inline-block;
+ font-weight: var(--font-weight-bold);
+ text-align: right;
+ width: 4em;
+ }
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
<style include="dashboard-header-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
<div class="info">
- <h1 class="heading-1">
- [[repo]]
- </h1>
+ <h1 class="heading-1">[[repo]]</h1>
<hr />
<div><span>Detail:</span> <a href$="[[_repoUrl]]">Repo settings</a></div>
+ <span is="dom-if" if="[[_webLinks]]">
+ <div>
+ <span class="browse">Browse:</span>
+ <template is="dom-repeat" items="[[_webLinks]]" as="weblink">
+ <a target="_blank" href$="[[weblink.url]]">[[weblink.name]]</a>
+ </template>
+ </div>
+ </span>
</div>
`;
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.js b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.js
index 4f93d54..f877e97 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_test.js
@@ -18,6 +18,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-repo-header.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
+import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-repo-header');
@@ -36,5 +37,24 @@
element.repo = 'test';
assert.equal(element._repoUrl, 'http://test.com/test');
});
-});
+ test('webLinks set', () => {
+ const repoRes = {
+ web_links: [
+ {
+ name: 'gitiles',
+ url: 'https://gerrit.test/g',
+ },
+ ],
+ };
+
+ stubRestApi('getRepo').returns(Promise.resolve(repoRes));
+
+ assert.deepEqual(element._webLinks, []);
+
+ element.repo = 'test';
+ flush(() => {
+ assert.deepEqual(element._webLinks, repoRes.web_links);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
index cfee0cd..5e4c361 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
@@ -21,8 +21,6 @@
import '../../shared/gr-avatar/gr-avatar';
import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../../styles/dashboard-header-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-user-header_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -32,9 +30,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-user-header')
-export class GrUserHeader extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrUserHeader extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
index a8a6a56..1924a66 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
@@ -33,9 +33,7 @@
aria-label="Account avatar"
></gr-avatar>
<div class="info">
- <h1 class="heading-1">
- [[_computeHeading(_accountDetails)]]
- </h1>
+ <h1 class="heading-1">[[_computeHeading(_accountDetails)]]</h1>
<hr />
<div class$="status [[_computeStatusClass(_status)]]">
<span>Status:</span> [[_status]]
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 87b09c7..db33344 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -30,8 +30,6 @@
import '../gr-confirm-submit-dialog/gr-confirm-submit-dialog';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-actions_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -113,6 +111,7 @@
RevisionActions,
} from '../../../api/change-actions';
import {ErrorCallback} from '../../../api/rest';
+import {GrDropdown} from '../../shared/gr-dropdown/gr-dropdown';
const ERR_BRANCH_EMPTY = 'The destination branch can’t be empty.';
const ERR_COMMIT_EMPTY = 'The commit message can’t be empty.';
@@ -173,7 +172,7 @@
method: HttpMethod.POST,
};
-function isQuckApproveAction(
+function isQuickApproveAction(
action: UIActionInfo
): action is QuickApproveUIActionInfo {
return (action as QuickApproveUIActionInfo).key === QUICK_APPROVE_ACTION.key;
@@ -276,7 +275,7 @@
ChangeActions.UNREVIEWED,
];
-function assertUIActionInfo(action?: ActionInfo): UIActionInfo {
+export function assertUIActionInfo(action?: ActionInfo): UIActionInfo {
// TODO(TS): Remove this function. The gr-change-actions adds properties
// to existing ActionInfo objects instead of creating a new objects. This
// function checks, that 'action' has all property required by UIActionInfo.
@@ -334,12 +333,14 @@
createFollowUpChange: GrCreateChangeDialog;
confirmDeleteDialog: GrDialog;
confirmDeleteEditDialog: GrDialog;
+ moreActions: GrDropdown;
+ secondaryActions: HTMLElement;
};
}
@customElement('gr-change-actions')
export class GrChangeActions
- extends GestureEventListeners(LegacyElementMixin(PolymerElement))
+ extends PolymerElement
implements GrChangeActionsElement {
static get template() {
return htmlTemplate;
@@ -555,9 +556,8 @@
private readonly restApiService = appContext.restApiService;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('fullscreen-overlay-opened', () =>
this._handleHideBackgroundContent()
);
@@ -947,9 +947,10 @@
const status = this._getLabelStatus(labelInfo);
if (status === LabelStatus.NEED) {
if (result) {
- // More than one label is missing, so it's unclear which to quick
- // approve, return null;
- return null;
+ // More than one label is missing, so check if Code Review can be
+ // given
+ result = null;
+ break;
}
result = label;
} else if (
@@ -1003,7 +1004,7 @@
throw new Error('_topLevelSecondaryActions must be set');
}
this._topLevelSecondaryActions = this._topLevelSecondaryActions.filter(
- sa => !isQuckApproveAction(sa)
+ sa => !isQuickApproveAction(sa)
);
this._hideQuickApproveAction = true;
}
@@ -1275,7 +1276,7 @@
this._showActionDialog(this.$.confirmAbandonDialog);
break;
case QUICK_APPROVE_ACTION.key: {
- const action = this._allActionValues.find(isQuckApproveAction);
+ const action = this._allActionValues.find(isQuickApproveAction);
if (!action) {
return;
}
@@ -2083,7 +2084,7 @@
}
if (attemptsRemaining) {
- this.async(check, AWAIT_CHANGE_TIMEOUT_MS);
+ setTimeout(check, AWAIT_CHANGE_TIMEOUT_MS);
} else {
resolve(false);
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
index 71500ac..023e801 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
@@ -90,6 +90,7 @@
has-tooltip="[[_computeHasTooltip(action.title)]]"
position-below="true"
data-action-key$="[[action.__key]]"
+ class$="[[action.__key]]"
data-action-type$="[[action.__type]]"
data-label$="[[action.label]]"
disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
@@ -118,6 +119,7 @@
has-tooltip="[[_computeHasTooltip(action.title)]]"
position-below="true"
data-action-key$="[[action.__key]]"
+ class$="[[action.__key]]"
data-action-type$="[[action.__type]]"
data-label$="[[action.label]]"
disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
@@ -226,9 +228,7 @@
on-confirm="_handleCreateFollowUpChange"
on-cancel="_handleCloseCreateFollowUpChange"
>
- <div class="header" slot="header">
- Create Follow-Up Change
- </div>
+ <div class="header" slot="header">Create Follow-Up Change</div>
<div class="main" slot="main">
<gr-create-change-dialog
id="createFollowUpChange"
@@ -247,9 +247,7 @@
on-cancel="_handleConfirmDialogCancel"
on-confirm="_handleDeleteConfirm"
>
- <div class="header" slot="header">
- Delete Change
- </div>
+ <div class="header" slot="header">Delete Change</div>
<div class="main" slot="main">
Do you really want to delete the change?
</div>
@@ -262,12 +260,8 @@
on-cancel="_handleConfirmDialogCancel"
on-confirm="_handleDeleteEditConfirm"
>
- <div class="header" slot="header">
- Delete Change Edit
- </div>
- <div class="main" slot="main">
- Do you really want to delete the edit?
- </div>
+ <div class="header" slot="header">Delete Change Edit</div>
+ <div class="main" slot="main">Do you really want to delete the edit?</div>
</gr-dialog>
</gr-overlay>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
deleted file mode 100644
index fbb70b7..0000000
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
+++ /dev/null
@@ -1,2149 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-change-actions.js';
-import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {
- createAccountWithId,
- createApproval,
- createChange,
- createChangeMessages,
- createRevisions,
-} from '../../../test/test-data-generators.js';
-import {ChangeStatus} from '../../../constants/constants.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-change-actions');
-
-const CHERRY_PICK_TYPES = {
- SINGLE_CHANGE: 1,
- TOPIC: 2,
-};
-// TODO(dhruvsri): remove use of _populateRevertMessage as it's private
-suite('gr-change-actions tests', () => {
- let element;
-
- suite('basic tests', () => {
- setup(() => {
- stubRestApi('getChangeRevisionActions').returns(Promise.resolve({
- cherrypick: {
- method: 'POST',
- label: 'Cherry Pick',
- title: 'Cherry pick change to a different branch',
- enabled: true,
- },
- rebase: {
- method: 'POST',
- label: 'Rebase',
- title: 'Rebase onto tip of branch or parent change',
- enabled: true,
- },
- submit: {
- method: 'POST',
- label: 'Submit',
- title: 'Submit patch set 2 into master',
- enabled: true,
- },
- revert_submission: {
- method: 'POST',
- label: 'Revert submission',
- title: 'Revert this submission',
- enabled: true,
- },
- }));
- stubRestApi('send').callsFake((method, url, payload) => {
- if (method !== 'POST') {
- return Promise.reject(new Error('bad method'));
- }
- if (url === '/changes/test~42/revisions/2/submit') {
- return Promise.resolve({
- ok: true,
- text() { return Promise.resolve(')]}\'\n{}'); },
- });
- } else if (url === '/changes/test~42/revisions/2/rebase') {
- return Promise.resolve({
- ok: true,
- text() { return Promise.resolve(')]}\'\n{}'); },
- });
- }
- return Promise.reject(new Error('bad url'));
- });
- stubRestApi('getProjectConfig').returns(Promise.resolve({}));
-
- sinon.stub(getPluginLoader(), 'awaitPluginsLoaded')
- .returns(Promise.resolve());
-
- element = basicFixture.instantiate();
- element.change = {};
- element.changeNum = '42';
- element.latestPatchNum = '2';
- element.actions = {
- '/': {
- method: 'DELETE',
- label: 'Delete Change',
- title: 'Delete change X_X',
- enabled: true,
- },
- };
- element.account = {
- _account_id: 123,
- };
- stubRestApi('getRepoBranches').returns(Promise.resolve([]));
-
- return element.reload();
- });
-
- test('show-revision-actions event should fire', done => {
- const spy = sinon.spy(element, '_sendShowRevisionActions');
- element.reload();
- flush(() => {
- assert.isTrue(spy.called);
- done();
- });
- });
-
- test('primary and secondary actions split properly', () => {
- // Submit should be the only primary action.
- assert.equal(element._topLevelPrimaryActions.length, 1);
- assert.equal(element._topLevelPrimaryActions[0].label, 'Submit');
- assert.equal(element._topLevelSecondaryActions.length,
- element._topLevelActions.length - 1);
- });
-
- test('revert submission action is skipped', () => {
- assert.equal(element._allActionValues.filter(action =>
- action.__key === 'submit').length, 1);
- assert.equal(element._allActionValues.filter(action =>
- action.__key === 'revert_submission').length, 0);
- });
-
- test('_shouldHideActions', () => {
- assert.isTrue(element._shouldHideActions(undefined, true));
- assert.isTrue(element._shouldHideActions({base: {}}, false));
- assert.isFalse(element._shouldHideActions({base: ['test']}, false));
- });
-
- test('plugin revision actions', done => {
- const stub = stubRestApi('getChangeActionURL').returns(
- Promise.resolve('the-url'));
- element.revisionActions = {
- 'plugin~action': {},
- };
- assert.isOk(element.revisionActions['plugin~action']);
- flush(() => {
- assert.isTrue(stub.calledWith(
- element.changeNum, element.latestPatchNum, '/plugin~action'));
- assert.equal(element.revisionActions['plugin~action'].__url, 'the-url');
- done();
- });
- });
-
- test('plugin change actions', async () => {
- const stub = stubRestApi('getChangeActionURL').returns(
- Promise.resolve('the-url'));
- element.actions = {
- 'plugin~action': {},
- };
- assert.isOk(element.actions['plugin~action']);
- await flush();
- assert.isTrue(stub.calledWith(
- element.changeNum, undefined, '/plugin~action'));
- assert.equal(element.actions['plugin~action'].__url, 'the-url');
- });
-
- test('not supported actions are filtered out', () => {
- element.revisionActions = {followup: {}};
- assert.equal(element.querySelectorAll(
- 'section gr-button[data-action-type="revision"]').length, 0);
- });
-
- test('getActionDetails', () => {
- element.revisionActions = {
- 'plugin~action': {},
- ...element.revisionActions,
- };
- assert.isUndefined(element.getActionDetails('rubbish'));
- assert.strictEqual(element.revisionActions['plugin~action'],
- element.getActionDetails('plugin~action'));
- assert.strictEqual(element.revisionActions['rebase'],
- element.getActionDetails('rebase'));
- });
-
- test('hide revision action', done => {
- flush(() => {
- const buttonEl = element.shadowRoot
- .querySelector('[data-action-key="submit"]');
- assert.isOk(buttonEl);
- assert.throws(element.setActionHidden.bind(element, 'invalid type'));
- element.setActionHidden(element.ActionType.REVISION,
- element.RevisionActions.SUBMIT, true);
- assert.lengthOf(element._hiddenActions, 1);
- element.setActionHidden(element.ActionType.REVISION,
- element.RevisionActions.SUBMIT, true);
- assert.lengthOf(element._hiddenActions, 1);
- flush(() => {
- const buttonEl = element.shadowRoot
- .querySelector('[data-action-key="submit"]');
- assert.isNotOk(buttonEl);
-
- element.setActionHidden(element.ActionType.REVISION,
- element.RevisionActions.SUBMIT, false);
- flush(() => {
- const buttonEl = element.shadowRoot
- .querySelector('[data-action-key="submit"]');
- assert.isOk(buttonEl);
- assert.isFalse(buttonEl.hasAttribute('hidden'));
- done();
- });
- });
- });
- });
-
- test('buttons exist', done => {
- element._loading = false;
- flush(() => {
- const buttonEls = dom(element.root)
- .querySelectorAll('gr-button');
- const menuItems = element.$.moreActions.items;
-
- // Total button number is one greater than the number of total actions
- // due to the existence of the overflow menu trigger.
- assert.equal(buttonEls.length + menuItems.length,
- element._allActionValues.length + 1);
- assert.isFalse(element.hidden);
- done();
- });
- });
-
- test('delete buttons have explicit labels', done => {
- flush(() => {
- const deleteItems = element.$.moreActions.items
- .filter(item => item.id.startsWith('delete'));
- assert.equal(deleteItems.length, 1);
- assert.notEqual(deleteItems[0].name);
- assert.equal(deleteItems[0].name, 'Delete change');
- done();
- });
- });
-
- test('get revision object from change', () => {
- const revObj = {_number: 2, foo: 'bar'};
- const change = {
- revisions: {
- rev1: {_number: 1},
- rev2: revObj,
- },
- };
- assert.deepEqual(element._getRevision(change, 2), revObj);
- });
-
- test('_actionComparator sort order', () => {
- const actions = [
- {label: '123', __type: 'change', __key: 'review'},
- {label: 'abc-ro', __type: 'revision'},
- {label: 'abc', __type: 'change'},
- {label: 'def', __type: 'change'},
- {label: 'def-p', __type: 'change', __primary: true},
- ];
-
- const result = actions.slice();
- result.reverse();
- result.sort(element._actionComparator.bind(element));
- assert.deepEqual(result, actions);
- });
-
- test('submit change', () => {
- const showSpy = sinon.spy(element, '_showActionDialog');
- stubRestApi('getFromProjectLookup')
- .returns(Promise.resolve('test'));
- sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
- element.change = {
- revisions: {
- rev1: {_number: 1},
- rev2: {_number: 2},
- },
- };
- element.latestPatchNum = '2';
-
- const submitButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="submit"]');
- assert.ok(submitButton);
- MockInteractions.tap(submitButton);
-
- flush();
- assert.isTrue(showSpy.calledWith(element.$.confirmSubmitDialog));
- });
-
- test('submit change, tap on icon', done => {
- sinon.stub(element.$.confirmSubmitDialog, 'resetFocus').callsFake( done);
- stubRestApi('getFromProjectLookup')
- .returns(Promise.resolve('test'));
- sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
- element.change = {
- revisions: {
- rev1: {_number: 1},
- rev2: {_number: 2},
- },
- };
- element.latestPatchNum = '2';
-
- const submitIcon =
- element.shadowRoot
- .querySelector('gr-button[data-action-key="submit"] iron-icon');
- assert.ok(submitIcon);
- MockInteractions.tap(submitIcon);
- });
-
- test('_handleSubmitConfirm', () => {
- const fireStub = sinon.stub(element, '_fireAction');
- sinon.stub(element, '_canSubmitChange').returns(true);
- element._handleSubmitConfirm();
- assert.isTrue(fireStub.calledOnce);
- assert.deepEqual(fireStub.lastCall.args,
- ['/submit', element.revisionActions.submit, true]);
- });
-
- test('_handleSubmitConfirm when not able to submit', () => {
- const fireStub = sinon.stub(element, '_fireAction');
- sinon.stub(element, '_canSubmitChange').returns(false);
- element._handleSubmitConfirm();
- assert.isFalse(fireStub.called);
- });
-
- test('submit change with plugin hook', done => {
- sinon.stub(element, '_canSubmitChange').callsFake(
- () => false);
- const fireActionStub = sinon.stub(element, '_fireAction');
- flush(() => {
- const submitButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="submit"]');
- assert.ok(submitButton);
- MockInteractions.tap(submitButton);
- assert.equal(fireActionStub.callCount, 0);
-
- done();
- });
- });
-
- test('chain state', () => {
- assert.equal(element._hasKnownChainState, false);
- element.hasParent = true;
- assert.equal(element._hasKnownChainState, true);
- element.hasParent = false;
- });
-
- test('_calculateDisabled', () => {
- let hasKnownChainState = false;
- const action = {__key: 'rebase', enabled: true};
- assert.equal(
- element._calculateDisabled(action, hasKnownChainState), true);
-
- action.__key = 'delete';
- assert.equal(
- element._calculateDisabled(action, hasKnownChainState), false);
-
- action.__key = 'rebase';
- hasKnownChainState = true;
- assert.equal(
- element._calculateDisabled(action, hasKnownChainState), false);
-
- action.enabled = false;
- assert.equal(
- element._calculateDisabled(action, hasKnownChainState), false);
- });
-
- test('rebase change', done => {
- const fireActionStub = sinon.stub(element, '_fireAction');
- const fetchChangesStub = sinon.stub(element.$.confirmRebase,
- 'fetchRecentChanges').returns(Promise.resolve([]));
- element._hasKnownChainState = true;
- flush(() => {
- const rebaseButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="rebase"]');
- MockInteractions.tap(rebaseButton);
- const rebaseAction = {
- __key: 'rebase',
- __type: 'revision',
- __primary: false,
- enabled: true,
- label: 'Rebase',
- method: 'POST',
- title: 'Rebase onto tip of branch or parent change',
- };
- assert.isTrue(fetchChangesStub.called);
- element._handleRebaseConfirm({detail: {base: '1234'}});
- assert.deepEqual(fireActionStub.lastCall.args,
- ['/rebase', rebaseAction, true, {base: '1234'}]);
- done();
- });
- });
-
- test('rebase change fires reload event', done => {
- const eventStub = sinon.stub(element, 'dispatchEvent');
- stubRestApi('getResponseObject').returns(
- Promise.resolve({}));
- element._handleResponse({__key: 'rebase'}, {});
- flush(() => {
- assert.isTrue(eventStub.called);
- assert.equal(eventStub.lastCall.args[0].type, 'reload');
- done();
- });
- });
-
- test(`rebase dialog gets recent changes each time it's opened`, done => {
- const fetchChangesStub = sinon.stub(element.$.confirmRebase,
- 'fetchRecentChanges').returns(Promise.resolve([]));
- element._hasKnownChainState = true;
- const rebaseButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="rebase"]');
- MockInteractions.tap(rebaseButton);
- assert.isTrue(fetchChangesStub.calledOnce);
-
- flush(() => {
- element.$.confirmRebase.dispatchEvent(
- new CustomEvent('cancel', {
- composed: true, bubbles: true,
- }));
- MockInteractions.tap(rebaseButton);
- assert.isTrue(fetchChangesStub.calledTwice);
- done();
- });
- });
-
- test('two dialogs are not shown at the same time', async () => {
- element._hasKnownChainState = true;
- await flush();
- const rebaseButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="rebase"]');
- assert.ok(rebaseButton);
- MockInteractions.tap(rebaseButton);
- await flush();
- assert.isFalse(element.$.confirmRebase.hidden);
- stubRestApi('getChanges')
- .returns(Promise.resolve([]));
- element._handleCherrypickTap();
- await flush();
- assert.isTrue(element.$.confirmRebase.hidden);
- assert.isFalse(element.$.confirmCherrypick.hidden);
- });
-
- test('fullscreen-overlay-opened hides content', () => {
- sinon.spy(element, '_handleHideBackgroundContent');
- element.$.overlay.dispatchEvent(
- new CustomEvent('fullscreen-overlay-opened', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(element._handleHideBackgroundContent.called);
- assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
- });
-
- test('fullscreen-overlay-closed shows content', () => {
- sinon.spy(element, '_handleShowBackgroundContent');
- element.$.overlay.dispatchEvent(
- new CustomEvent('fullscreen-overlay-closed', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(element._handleShowBackgroundContent.called);
- assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
- });
-
- test('_setReviewOnRevert', () => {
- const review = {labels: {'Foo': 1, 'Bar-Baz': -2}};
- const changeId = 1234;
- sinon.stub(element.jsAPI, 'getReviewPostRevert').returns(review);
- const saveStub = stubRestApi('saveChangeReview')
- .returns(Promise.resolve());
- return element._setReviewOnRevert(changeId).then(() => {
- assert.isTrue(saveStub.calledOnce);
- assert.equal(saveStub.lastCall.args[0], changeId);
- assert.deepEqual(saveStub.lastCall.args[2], review);
- });
- });
-
- suite('change edits', () => {
- test('disableEdit', () => {
- element.set('editMode', false);
- element.set('editPatchsetLoaded', false);
- element.change = {status: 'NEW'};
- element.set('disableEdit', true);
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- });
-
- test('shows confirm dialog for delete edit', () => {
- element.set('editMode', true);
- element.set('editPatchsetLoaded', true);
-
- const fireActionStub = sinon.stub(element, '_fireAction');
- element._handleDeleteEditTap();
- assert.isFalse(element.$.confirmDeleteEditDialog.hidden);
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('#confirmDeleteEditDialog')
- .shadowRoot
- .querySelector('gr-button[primary]'));
- flush();
-
- assert.equal(fireActionStub.lastCall.args[0], '/edit');
- });
-
- test('hide publishEdit and rebaseEdit if change is not open', () => {
- element.set('editMode', true);
- element.set('editPatchsetLoaded', true);
- element.change = {status: 'MERGED'};
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- });
-
- test('edit patchset is loaded, needs rebase', () => {
- element.set('editMode', true);
- element.set('editPatchsetLoaded', true);
- element.change = {status: 'NEW'};
- element.editBasedOnCurrentPatchSet = false;
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- });
-
- test('edit patchset is loaded, does not need rebase', () => {
- element.set('editMode', true);
- element.set('editPatchsetLoaded', true);
- element.change = {status: 'NEW'};
- element.editBasedOnCurrentPatchSet = true;
- flush();
-
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- });
-
- test('edit mode is loaded, no edit patchset', () => {
- element.set('editMode', true);
- element.set('editPatchsetLoaded', false);
- element.change = {status: 'NEW'};
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- });
-
- test('normal patch set', () => {
- element.set('editMode', false);
- element.set('editPatchsetLoaded', false);
- element.change = {status: 'NEW'};
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="publishEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="rebaseEdit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="deleteEdit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- });
-
- test('edit action', done => {
- element.addEventListener('edit-tap', () => { done(); });
- element.set('editMode', true);
- element.change = {status: 'NEW'};
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- assert.isOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="stopEdit"]'));
- element.change = {status: 'MERGED'};
- flush();
-
- assert.isNotOk(element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]'));
- element.change = {status: 'NEW'};
- element.set('editMode', false);
- flush();
-
- const editButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="edit"]');
- assert.isOk(editButton);
- MockInteractions.tap(editButton);
- });
- });
-
- suite('cherry-pick', () => {
- let fireActionStub;
-
- setup(() => {
- fireActionStub = sinon.stub(element, '_fireAction');
- sinon.stub(window, 'alert');
- });
-
- test('works', () => {
- element._handleCherrypickTap();
- const action = {
- __key: 'cherrypick',
- __type: 'revision',
- __primary: false,
- enabled: true,
- label: 'Cherry pick',
- method: 'POST',
- title: 'Cherry pick change to a different branch',
- };
-
- element._handleCherrypickConfirm({
- detail: {
- branch: '',
- type: CHERRY_PICK_TYPES.SINGLE_CHANGE,
- },
- });
- assert.equal(fireActionStub.callCount, 0);
-
- element.$.confirmCherrypick.branch = 'master';
- element._handleCherrypickConfirm({
- detail: {
- branch: 'master',
- type: CHERRY_PICK_TYPES.SINGLE_CHANGE,
- },
- });
- assert.equal(fireActionStub.callCount, 0); // Still needs a message.
-
- // Add attributes that are used to determine the message.
- element.$.confirmCherrypick.commitMessage = 'foo message';
- element.$.confirmCherrypick.changeStatus = 'OPEN';
- element.$.confirmCherrypick.commitNum = '123';
-
- element._handleCherrypickConfirm({
- detail: {
- branch: 'master',
- type: CHERRY_PICK_TYPES.SINGLE_CHANGE,
- },
- });
-
- assert.equal(element.$.confirmCherrypick.shadowRoot.
- querySelector('#messageInput').value, 'foo message');
-
- assert.deepEqual(fireActionStub.lastCall.args, [
- '/cherrypick', action, true, {
- destination: 'master',
- base: null,
- message: 'foo message',
- allow_conflicts: false,
- },
- ]);
- });
-
- test('cherry pick even with conflicts', () => {
- element._handleCherrypickTap();
- const action = {
- __key: 'cherrypick',
- __type: 'revision',
- __primary: false,
- enabled: true,
- label: 'Cherry pick',
- method: 'POST',
- title: 'Cherry pick change to a different branch',
- };
-
- element.$.confirmCherrypick.branch = 'master';
-
- // Add attributes that are used to determine the message.
- element.$.confirmCherrypick.commitMessage = 'foo message';
- element.$.confirmCherrypick.changeStatus = 'OPEN';
- element.$.confirmCherrypick.commitNum = '123';
-
- element._handleCherrypickConflictConfirm();
-
- assert.deepEqual(fireActionStub.lastCall.args, [
- '/cherrypick', action, true, {
- destination: 'master',
- base: null,
- message: 'foo message',
- allow_conflicts: true,
- },
- ]);
- });
-
- test('branch name cleared when re-open cherrypick', () => {
- const emptyBranchName = '';
- element.$.confirmCherrypick.branch = 'master';
-
- element._handleCherrypickTap();
- assert.equal(element.$.confirmCherrypick.branch, emptyBranchName);
- });
-
- suite('cherry pick topics', () => {
- const changes = [
- {
- change_id: '12345678901234', topic: 'T', subject: 'random',
- project: 'A', status: 'MERGED',
- },
- {
- change_id: '23456', topic: 'T', subject: 'a'.repeat(100),
- project: 'B', status: 'NEW',
- },
- ];
- setup(done => {
- stubRestApi('getChanges')
- .returns(Promise.resolve(changes));
- element._handleCherrypickTap();
- flush(() => {
- const radioButtons = element.$.confirmCherrypick.shadowRoot.
- querySelectorAll(`input[name='cherryPickOptions']`);
- assert.equal(radioButtons.length, 2);
- MockInteractions.tap(radioButtons[1]);
- flush(() => {
- done();
- });
- });
- });
-
- test('cherry pick topic dialog is rendered', done => {
- const dialog = element.$.confirmCherrypick;
- flush(() => {
- const changesTable = dialog.shadowRoot.querySelector('table');
- const headers = Array.from(changesTable.querySelectorAll('th'));
- const expectedHeadings = ['', 'Change', 'Status', 'Subject',
- 'Project', 'Progress', ''];
- const headings = headers.map(header => header.innerText);
- assert.equal(headings.length, expectedHeadings.length);
- for (let i = 0; i < headings.length; i++) {
- assert.equal(headings[i].trim(), expectedHeadings[i]);
- }
- const changeRows = changesTable.querySelectorAll('tbody > tr');
- const change = Array.from(changeRows[0].querySelectorAll('td'))
- .map(e => e.innerText);
- const expectedChange = ['', '1234567890', 'MERGED', 'random', 'A',
- 'NOT STARTED', ''];
- for (let i = 0; i < change.length; i++) {
- assert.equal(change[i].trim(), expectedChange[i]);
- }
- done();
- });
- });
-
- test('changes with duplicate project show an error', done => {
- const dialog = element.$.confirmCherrypick;
- const error = dialog.shadowRoot.querySelector('.error-message');
- assert.equal(error.innerText, '');
- dialog.updateChanges([
- {
- change_id: '12345678901234', topic: 'T', subject: 'random',
- project: 'A',
- },
- {
- change_id: '23456', topic: 'T', subject: 'a'.repeat(100),
- project: 'A',
- },
- ]);
- flush(() => {
- assert.equal(error.innerText, 'Two changes cannot be of the same'
- + ' project');
- done();
- });
- });
- });
- });
-
- suite('move change', () => {
- let fireActionStub;
-
- setup(() => {
- fireActionStub = sinon.stub(element, '_fireAction');
- sinon.stub(window, 'alert');
- element.actions = {
- move: {
- method: 'POST',
- label: 'Move',
- title: 'Move the change',
- enabled: true,
- },
- };
- });
-
- test('works', () => {
- element._handleMoveTap();
-
- element._handleMoveConfirm();
- assert.equal(fireActionStub.callCount, 0);
-
- element.$.confirmMove.branch = 'master';
- element._handleMoveConfirm();
- assert.equal(fireActionStub.callCount, 1);
- });
-
- test('branch name cleared when re-open move', () => {
- const emptyBranchName = '';
- element.$.confirmMove.branch = 'master';
-
- element._handleMoveTap();
- assert.equal(element.$.confirmMove.branch, emptyBranchName);
- });
- });
-
- test('custom actions', done => {
- // Add a button with the same key as a server-based one to ensure
- // collisions are taken care of.
- const key = element.addActionButton(element.ActionType.REVISION, 'Bork!');
- element.addEventListener(key + '-tap', e => {
- assert.equal(e.detail.node.getAttribute('data-action-key'), key);
- element.removeActionButton(key);
- flush(() => {
- assert.notOk(element.shadowRoot
- .querySelector('[data-action-key="' + key + '"]'));
- done();
- });
- });
- flush(() => {
- MockInteractions.tap(element.shadowRoot
- .querySelector('[data-action-key="' + key + '"]'));
- });
- });
-
- test('_setLoadingOnButtonWithKey top-level', () => {
- const key = 'rebase';
- const type = 'revision';
- const cleanup = element._setLoadingOnButtonWithKey(type, key);
- assert.equal(element._actionLoadingMessage, 'Rebasing...');
-
- const button = element.shadowRoot
- .querySelector('[data-action-key="' + key + '"]');
- assert.isTrue(button.hasAttribute('loading'));
- assert.isTrue(button.disabled);
-
- assert.isOk(cleanup);
- assert.isFunction(cleanup);
- cleanup();
-
- assert.isFalse(button.hasAttribute('loading'));
- assert.isFalse(button.disabled);
- assert.isNotOk(element._actionLoadingMessage);
- });
-
- test('_setLoadingOnButtonWithKey overflow menu', () => {
- const key = 'cherrypick';
- const type = 'revision';
- const cleanup = element._setLoadingOnButtonWithKey(type, key);
- assert.equal(element._actionLoadingMessage, 'Cherry-picking...');
- assert.include(element._disabledMenuActions, 'cherrypick');
- assert.isFunction(cleanup);
-
- cleanup();
-
- assert.notOk(element._actionLoadingMessage);
- assert.notInclude(element._disabledMenuActions, 'cherrypick');
- });
-
- suite('abandon change', () => {
- let alertStub;
- let fireActionStub;
-
- setup(() => {
- fireActionStub = sinon.stub(element, '_fireAction');
- alertStub = sinon.stub(window, 'alert');
- element.actions = {
- abandon: {
- method: 'POST',
- label: 'Abandon',
- title: 'Abandon the change',
- enabled: true,
- },
- };
- return element.reload();
- });
-
- test('abandon change with message', done => {
- const newAbandonMsg = 'Test Abandon Message';
- element.$.confirmAbandonDialog.message = newAbandonMsg;
- flush(() => {
- const abandonButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key="abandon"]');
- MockInteractions.tap(abandonButton);
-
- assert.equal(element.$.confirmAbandonDialog.message, newAbandonMsg);
- done();
- });
- });
-
- test('abandon change with no message', done => {
- flush(() => {
- const abandonButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key="abandon"]');
- MockInteractions.tap(abandonButton);
-
- assert.isUndefined(element.$.confirmAbandonDialog.message);
- done();
- });
- });
-
- test('works', () => {
- element.$.confirmAbandonDialog.message = 'original message';
- const restoreButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key="abandon"]');
- MockInteractions.tap(restoreButton);
-
- element.$.confirmAbandonDialog.message = 'foo message';
- element._handleAbandonDialogConfirm();
- assert.notOk(alertStub.called);
-
- const action = {
- __key: 'abandon',
- __type: 'change',
- __primary: false,
- enabled: true,
- label: 'Abandon',
- method: 'POST',
- title: 'Abandon the change',
- };
- assert.deepEqual(fireActionStub.lastCall.args, [
- '/abandon', action, false, {
- message: 'foo message',
- }]);
- });
- });
-
- suite('revert change', () => {
- let fireActionStub;
-
- setup(() => {
- fireActionStub = sinon.stub(element, '_fireAction');
- element.commitMessage = 'random commit message';
- element.change.current_revision = 'abcdef';
- element.actions = {
- revert: {
- method: 'POST',
- label: 'Revert',
- title: 'Revert the change',
- enabled: true,
- },
- };
- return element.reload();
- });
-
- test('revert change with plugin hook', done => {
- const newRevertMsg = 'Modified revert msg';
- sinon.stub(element.$.confirmRevertDialog, '_modifyRevertMsg').callsFake(
- () => newRevertMsg);
- element.change = {
- current_revision: 'abc1234',
- };
- stubRestApi('getChanges')
- .returns(Promise.resolve([
- {change_id: '12345678901234', topic: 'T', subject: 'random'},
- {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
- ]));
- sinon.stub(element.$.confirmRevertDialog,
- '_populateRevertSubmissionMessage').callsFake(() => 'original msg');
- flush(() => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- MockInteractions.tap(revertButton);
- flush(() => {
- assert.equal(element.$.confirmRevertDialog._message, newRevertMsg);
- done();
- });
- });
- });
-
- suite('revert change submitted together', () => {
- let getChangesStub;
- setup(() => {
- element.change = {
- submission_id: '199 0',
- current_revision: '2000',
- };
- getChangesStub = stubRestApi('getChanges')
- .returns(Promise.resolve([
- {change_id: '12345678901234', topic: 'T', subject: 'random'},
- {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
- ]));
- });
-
- test('confirm revert dialog shows both options', done => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- MockInteractions.tap(revertButton);
- flush(() => {
- assert.equal(getChangesStub.args[0][1], 'submissionid: "199 0"');
- const confirmRevertDialog = element.$.confirmRevertDialog;
- const revertSingleChangeLabel = confirmRevertDialog
- .shadowRoot.querySelector('.revertSingleChange');
- const revertSubmissionLabel = confirmRevertDialog.
- shadowRoot.querySelector('.revertSubmission');
- assert(revertSingleChangeLabel.innerText.trim() ===
- 'Revert single change');
- assert(revertSubmissionLabel.innerText.trim() ===
- 'Revert entire submission (2 Changes)');
- let expectedMsg = 'Revert submission 199 0' + '\n\n' +
- 'Reason for revert: <INSERT REASONING HERE>' + '\n' +
- 'Reverted Changes:' + '\n' +
- '1234567890:random' + '\n' +
- '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
- '\n';
- assert.equal(confirmRevertDialog._message, expectedMsg);
- const radioInputs = confirmRevertDialog.shadowRoot
- .querySelectorAll('input[name="revertOptions"]');
- MockInteractions.tap(radioInputs[0]);
- flush(() => {
- expectedMsg = 'Revert "random commit message"\n\nThis reverts '
- + 'commit 2000.\n\nReason'
- + ' for revert: <INSERT REASONING HERE>\n';
- assert.equal(confirmRevertDialog._message, expectedMsg);
- done();
- });
- });
- });
-
- test('submit fails if message is not edited', done => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- const confirmRevertDialog = element.$.confirmRevertDialog;
- MockInteractions.tap(revertButton);
- const fireStub = sinon.stub(confirmRevertDialog, 'dispatchEvent');
- flush(() => {
- const confirmButton = element.$.confirmRevertDialog.shadowRoot
- .querySelector('gr-dialog')
- .shadowRoot.querySelector('#confirm');
- MockInteractions.tap(confirmButton);
- flush(() => {
- assert.isTrue(confirmRevertDialog._showErrorMessage);
- assert.isFalse(fireStub.called);
- done();
- });
- });
- });
-
- test('message modification is retained on switching', done => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- const confirmRevertDialog = element.$.confirmRevertDialog;
- MockInteractions.tap(revertButton);
- flush(() => {
- const radioInputs = confirmRevertDialog.shadowRoot
- .querySelectorAll('input[name="revertOptions"]');
- const revertSubmissionMsg = 'Revert submission 199 0' + '\n\n' +
- 'Reason for revert: <INSERT REASONING HERE>' + '\n' +
- 'Reverted Changes:' + '\n' +
- '1234567890:random' + '\n' +
- '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
- '\n';
- const singleChangeMsg =
- 'Revert "random commit message"\n\nThis reverts '
- + 'commit 2000.\n\nReason'
- + ' for revert: <INSERT REASONING HERE>\n';
- assert.equal(confirmRevertDialog._message, revertSubmissionMsg);
- const newRevertMsg = revertSubmissionMsg + 'random';
- const newSingleChangeMsg = singleChangeMsg + 'random';
- confirmRevertDialog._message = newRevertMsg;
- MockInteractions.tap(radioInputs[0]);
- flush(() => {
- assert.equal(confirmRevertDialog._message, singleChangeMsg);
- confirmRevertDialog._message = newSingleChangeMsg;
- MockInteractions.tap(radioInputs[1]);
- flush(() => {
- assert.equal(confirmRevertDialog._message, newRevertMsg);
- MockInteractions.tap(radioInputs[0]);
- flush(() => {
- assert.equal(
- confirmRevertDialog._message,
- newSingleChangeMsg
- );
- done();
- });
- });
- });
- });
- });
- });
-
- suite('revert single change', () => {
- setup(() => {
- element.change = {
- submission_id: '199',
- current_revision: '2000',
- };
- stubRestApi('getChanges')
- .returns(Promise.resolve([
- {change_id: '12345678901234', topic: 'T', subject: 'random'},
- ]));
- });
-
- test('submit fails if message is not edited', done => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- const confirmRevertDialog = element.$.confirmRevertDialog;
- MockInteractions.tap(revertButton);
- const fireStub = sinon.stub(confirmRevertDialog, 'dispatchEvent');
- flush(() => {
- const confirmButton = element.$.confirmRevertDialog.shadowRoot
- .querySelector('gr-dialog')
- .shadowRoot.querySelector('#confirm');
- MockInteractions.tap(confirmButton);
- flush(() => {
- assert.isTrue(confirmRevertDialog._showErrorMessage);
- assert.isFalse(fireStub.called);
- done();
- });
- });
- });
-
- test('confirm revert dialog shows no radio button', done => {
- const revertButton = element.shadowRoot
- .querySelector('gr-button[data-action-key="revert"]');
- MockInteractions.tap(revertButton);
- flush(() => {
- const confirmRevertDialog = element.$.confirmRevertDialog;
- const radioInputs = confirmRevertDialog.shadowRoot
- .querySelectorAll('input[name="revertOptions"]');
- assert.equal(radioInputs.length, 0);
- const msg = 'Revert "random commit message"\n\n'
- + 'This reverts commit 2000.\n\nReason '
- + 'for revert: <INSERT REASONING HERE>\n';
- assert.equal(confirmRevertDialog._message, msg);
- const editedMsg = msg + 'hello';
- confirmRevertDialog._message += 'hello';
- const confirmButton = element.$.confirmRevertDialog.shadowRoot
- .querySelector('gr-dialog')
- .shadowRoot.querySelector('#confirm');
- MockInteractions.tap(confirmButton);
- flush(() => {
- assert.equal(fireActionStub.getCall(0).args[0], '/revert');
- assert.equal(fireActionStub.getCall(0).args[1].__key, 'revert');
- assert.equal(fireActionStub.getCall(0).args[3].message,
- editedMsg);
- done();
- });
- });
- });
- });
- });
-
- suite('mark change private', () => {
- setup(() => {
- const privateAction = {
- __key: 'private',
- __type: 'change',
- __primary: false,
- method: 'POST',
- label: 'Mark private',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- private: privateAction,
- };
-
- element.change.is_private = false;
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- return element.reload();
- });
-
- test('make sure the mark private change button is not outside of the ' +
- 'overflow menu', done => {
- flush(() => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="private"]'));
- done();
- });
- });
-
- test('private change', done => {
- flush(() => {
- assert.isOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="private-change"]'));
- element.setActionOverflow('change', 'private', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="private"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="private-change"]'));
- done();
- });
- });
- });
-
- suite('unmark private change', () => {
- setup(() => {
- const unmarkPrivateAction = {
- __key: 'private.delete',
- __type: 'change',
- __primary: false,
- method: 'POST',
- label: 'Unmark private',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- 'private.delete': unmarkPrivateAction,
- };
-
- element.change.is_private = true;
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- return element.reload();
- });
-
- test('make sure the unmark private change button is not outside of the ' +
- 'overflow menu', done => {
- flush(() => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="private.delete"]'));
- done();
- });
- });
-
- test('unmark the private change', done => {
- flush(() => {
- assert.isOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="private.delete-change"]')
- );
- element.setActionOverflow('change', 'private.delete', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="private.delete"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="private.delete-change"]')
- );
- done();
- });
- });
- });
-
- suite('delete change', () => {
- let fireActionStub;
- let deleteAction;
-
- setup(() => {
- fireActionStub = sinon.stub(element, '_fireAction');
- element.change = {
- current_revision: 'abc1234',
- };
- deleteAction = {
- method: 'DELETE',
- label: 'Delete Change',
- title: 'Delete change X_X',
- enabled: true,
- };
- element.actions = {
- '/': deleteAction,
- };
- });
-
- test('does not delete on action', () => {
- element._handleDeleteTap();
- assert.isFalse(fireActionStub.called);
- });
-
- test('shows confirm dialog', () => {
- element._handleDeleteTap();
- assert.isFalse(element.shadowRoot
- .querySelector('#confirmDeleteDialog').hidden);
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('#confirmDeleteDialog')
- .shadowRoot
- .querySelector('gr-button[primary]'));
- flush();
- assert.isTrue(fireActionStub.calledWith('/', deleteAction, false));
- });
-
- test('hides delete confirm on cancel', () => {
- element._handleDeleteTap();
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('#confirmDeleteDialog')
- .shadowRoot
- .querySelector('gr-button:not([primary])'));
- flush();
- assert.isTrue(element.shadowRoot
- .querySelector('#confirmDeleteDialog').hidden);
- assert.isFalse(fireActionStub.called);
- });
- });
-
- suite('ignore change', () => {
- setup(done => {
- sinon.stub(element, '_fireAction');
-
- const IgnoreAction = {
- __key: 'ignore',
- __type: 'change',
- __primary: false,
- method: 'PUT',
- label: 'Ignore',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- ignore: IgnoreAction,
- };
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- element.reload().then(() => { flush(done); });
- });
-
- test('make sure the ignore button is not outside of the overflow menu',
- () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="ignore"]'));
- });
-
- test('ignoring change', () => {
- assert.isOk(element.$.moreActions.shadowRoot
- .querySelector('span[data-id="ignore-change"]'));
- element.setActionOverflow('change', 'ignore', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="ignore"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="ignore-change"]'));
- });
- });
-
- suite('unignore change', () => {
- setup(done => {
- sinon.stub(element, '_fireAction');
-
- const UnignoreAction = {
- __key: 'unignore',
- __type: 'change',
- __primary: false,
- method: 'PUT',
- label: 'Unignore',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- unignore: UnignoreAction,
- };
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- element.reload().then(() => { flush(done); });
- });
-
- test('unignore button is not outside of the overflow menu', () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="unignore"]'));
- });
-
- test('unignoring change', () => {
- assert.isOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="unignore-change"]'));
- element.setActionOverflow('change', 'unignore', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="unignore"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="unignore-change"]'));
- });
- });
-
- suite('reviewed change', () => {
- setup(done => {
- sinon.stub(element, '_fireAction');
-
- const ReviewedAction = {
- __key: 'reviewed',
- __type: 'change',
- __primary: false,
- method: 'PUT',
- label: 'Mark reviewed',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- reviewed: ReviewedAction,
- };
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- element.reload().then(() => { flush(done); });
- });
-
- test('action is enabled', () => {
- assert.equal(element._allActionValues.filter(action =>
- action.__key === 'reviewed').length, 1);
- });
-
- test('action is skipped when attention set is enabled', () => {
- element._config = {
- change: {enable_attention_set: true},
- };
- assert.equal(element._allActionValues.filter(action =>
- action.__key === 'reviewed').length, 0);
- });
-
- test('make sure the reviewed button is not outside of the overflow menu',
- () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="reviewed"]'));
- });
-
- test('reviewing change', () => {
- assert.isOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="reviewed-change"]'));
- element.setActionOverflow('change', 'reviewed', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="reviewed"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="reviewed-change"]'));
- });
- });
-
- suite('unreviewed change', () => {
- setup(done => {
- sinon.stub(element, '_fireAction');
-
- const UnreviewedAction = {
- __key: 'unreviewed',
- __type: 'change',
- __primary: false,
- method: 'PUT',
- label: 'Mark unreviewed',
- title: 'Working...',
- enabled: true,
- };
-
- element.actions = {
- unreviewed: UnreviewedAction,
- };
-
- element.changeNum = '2';
- element.latestPatchNum = '2';
-
- element.reload().then(() => { flush(done); });
- });
-
- test('unreviewed button not outside of the overflow menu', () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="unreviewed"]'));
- });
-
- test('unreviewed change', () => {
- assert.isOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="unreviewed-change"]'));
- element.setActionOverflow('change', 'unreviewed', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="unreviewed"]'));
- assert.isNotOk(
- element.$.moreActions.shadowRoot
- .querySelector('span[data-id="unreviewed-change"]'));
- });
- });
-
- suite('quick approve', () => {
- setup(() => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- foo: {
- values: {
- '-1': '',
- ' 0': '',
- '+1': '',
- },
- },
- },
- permitted_labels: {
- foo: ['-1', ' 0', '+1'],
- },
- };
- flush();
- });
-
- test('added when can approve', () => {
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNotNull(approveButton);
- });
-
- test('hide quick approve', () => {
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNotNull(approveButton);
- assert.isFalse(element._hideQuickApproveAction);
-
- // Assert approve button gets removed from list of buttons.
- element.hideQuickApproveAction();
- flush();
- const approveButtonUpdated =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButtonUpdated);
- assert.isTrue(element._hideQuickApproveAction);
- });
-
- test('is first in list of secondary actions', () => {
- const approveButton = element.$.secondaryActions
- .querySelector('gr-button');
- assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
- });
-
- test('not added when change is merged', () => {
- element.change.status = ChangeStatus.MERGED;
- flush(() => {
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
- });
-
- test('not added when already approved', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- foo: {
- approved: {},
- values: {},
- },
- },
- permitted_labels: {
- foo: [' 0', '+1'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
-
- test('not added when label not permitted', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- foo: {values: {}},
- },
- permitted_labels: {
- bar: [],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
-
- test('approves when tapped', () => {
- const fireActionStub = sinon.stub(element, '_fireAction');
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']'));
- flush();
- assert.isTrue(fireActionStub.called);
- assert.isTrue(fireActionStub.calledWith('/review'));
- const payload = fireActionStub.lastCall.args[3];
- assert.deepEqual(payload.labels, {foo: 1});
- });
-
- test('not added when multiple labels are required', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- foo: {values: {}},
- bar: {values: {}},
- },
- permitted_labels: {
- foo: [' 0', '+1'],
- bar: [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
-
- test('button label for missing approval', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- foo: {
- values: {
- ' 0': '',
- '+1': '',
- },
- },
- bar: {approved: {}, values: {}},
- },
- permitted_labels: {
- foo: [' 0', '+1'],
- bar: [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
- });
-
- test('no quick approve if score is not maximal for a label', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- bar: {
- value: 1,
- values: {
- ' 0': '',
- '+1': '',
- '+2': '',
- },
- },
- },
- permitted_labels: {
- bar: [' 0', '+1'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
-
- test('approving label with a non-max score', () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- bar: {
- value: 1,
- values: {
- ' 0': '',
- '+1': '',
- '+2': '',
- },
- },
- },
- permitted_labels: {
- bar: [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.equal(approveButton.getAttribute('data-label'), 'bar+2');
- });
-
- test('added when can approve an already-approved code review label',
- () => {
- element.change = {
- current_revision: 'abc1234',
- labels: {
- 'Code-Review': {
- approved: {},
- values: {
- ' 0': '',
- '+1': '',
- '+2': '',
- },
- },
- },
- permitted_labels: {
- 'Code-Review': [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNotNull(approveButton);
- });
-
- test('not added when the user has already approved', () => {
- const vote = {
- ...createApproval(),
- _account_id: 123,
- name: 'name',
- value: 2,
- };
- element.change = {
- current_revision: 'abc1234',
- labels: {
- 'Code-Review': {
- approved: {},
- values: {
- ' 0': '',
- '+1': '',
- '+2': '',
- },
- all: [vote],
- },
- },
- permitted_labels: {
- 'Code-Review': [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
-
- test('not added when user owns the change', () => {
- element.change = {
- current_revision: 'abc1234',
- owner: createAccountWithId(123),
- labels: {
- 'Code-Review': {
- approved: {},
- values: {
- ' 0': '',
- '+1': '',
- '+2': '',
- },
- },
- },
- permitted_labels: {
- 'Code-Review': [' 0', '+1', '+2'],
- },
- };
- flush();
- const approveButton =
- element.shadowRoot
- .querySelector('gr-button[data-action-key=\'review\']');
- assert.isNull(approveButton);
- });
- });
-
- test('adds download revision action', () => {
- const handler = sinon.stub();
- element.addEventListener('download-tap', handler);
- assert.ok(element.revisionActions.download);
- element._handleDownloadTap();
- flush();
-
- assert.isTrue(handler.called);
- });
-
- test('changing changeNum or patchNum does not reload', () => {
- const reloadStub = sinon.stub(element, 'reload');
- element.changeNum = 123;
- assert.isFalse(reloadStub.called);
- element.latestPatchNum = 456;
- assert.isFalse(reloadStub.called);
- });
-
- test('_toSentenceCase', () => {
- assert.equal(element._toSentenceCase('blah blah'), 'Blah blah');
- assert.equal(element._toSentenceCase('BLAH BLAH'), 'Blah blah');
- assert.equal(element._toSentenceCase('b'), 'B');
- assert.equal(element._toSentenceCase(''), '');
- assert.equal(element._toSentenceCase('!@#$%^&*()'), '!@#$%^&*()');
- });
-
- suite('setActionOverflow', () => {
- test('move action from overflow', () => {
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="cherrypick"]'));
- assert.strictEqual(
- element.$.moreActions.items[0].id, 'cherrypick-revision');
- element.setActionOverflow('revision', 'cherrypick', false);
- flush();
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="cherrypick"]'));
- assert.notEqual(
- element.$.moreActions.items[0].id, 'cherrypick-revision');
- });
-
- test('move action to overflow', () => {
- assert.isOk(element.shadowRoot
- .querySelector('[data-action-key="submit"]'));
- element.setActionOverflow('revision', 'submit', true);
- flush();
- assert.isNotOk(element.shadowRoot
- .querySelector('[data-action-key="submit"]'));
- assert.strictEqual(
- element.$.moreActions.items[3].id, 'submit-revision');
- });
-
- suite('_waitForChangeReachable', () => {
- setup(() => {
- sinon.stub(element, 'async').callsFake( fn => fn());
- });
-
- const makeGetChange = numTries => () => {
- if (numTries === 1) {
- return Promise.resolve({_number: 123});
- } else {
- numTries--;
- return Promise.resolve(undefined);
- }
- };
-
- test('succeed', () => {
- stubRestApi('getChange')
- .callsFake( makeGetChange(5));
- return element._waitForChangeReachable(123).then(success => {
- assert.isTrue(success);
- });
- });
-
- test('fail', () => {
- stubRestApi('getChange')
- .callsFake( makeGetChange(6));
- return element._waitForChangeReachable(123).then(success => {
- assert.isFalse(success);
- });
- });
- });
- });
-
- suite('_send', () => {
- let cleanup;
- let payload;
- let onShowError;
- let onShowAlert;
- let getResponseObjectStub;
-
- setup(() => {
- cleanup = sinon.stub();
- element.changeNum = 42;
- element.change._number = 42;
- element.latestPatchNum = 12;
- element.change = {
- ...createChange(),
- revisions: createRevisions(element.latestPatchNum),
- messages: createChangeMessages(1),
- };
- payload = {foo: 'bar'};
-
- onShowError = sinon.stub();
- element.addEventListener('show-error', onShowError);
- onShowAlert = sinon.stub();
- element.addEventListener('show-alert', onShowAlert);
- });
-
- suite('happy path', () => {
- let sendStub;
- setup(() => {
- stubRestApi('getChangeDetail')
- .returns(Promise.resolve({
- ...createChange(),
- // element has latest info
- revisions: createRevisions(element.latestPatchNum),
- messages: createChangeMessages(1),
- }));
- sendStub = stubRestApi('executeChangeAction')
- .returns(Promise.resolve({}));
- getResponseObjectStub = stubRestApi(
- 'getResponseObject');
- sinon.stub(GerritNav,
- 'navigateToChange').returns(Promise.resolve(true));
- });
-
- test('change action', async () => {
- await element._send('DELETE', payload, '/endpoint', false, cleanup);
- assert.isFalse(onShowError.called);
- assert.isTrue(cleanup.calledOnce);
- assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
- undefined, payload));
- });
-
- suite('show revert submission dialog', () => {
- setup(() => {
- element.change.submission_id = '199';
- element.change.current_revision = '2000';
- stubRestApi('getChanges')
- .returns(Promise.resolve([
- {change_id: '12345678901234', topic: 'T', subject: 'random'},
- {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
- ]));
- });
-
- test('revert submission shows submissionId', done => {
- const expectedMsg = 'Revert submission 199' + '\n\n' +
- 'Reason for revert: <INSERT REASONING HERE>' + '\n' +
- 'Reverted Changes:' + '\n' +
- '1234567890: random' + '\n' +
- '23456: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
- '\n';
- const modifiedMsg = expectedMsg + 'abcd';
- sinon.stub(element.$.confirmRevertSubmissionDialog,
- '_modifyRevertSubmissionMsg').returns(modifiedMsg);
- element.showRevertSubmissionDialog();
- flush(() => {
- const msg = element.$.confirmRevertSubmissionDialog.message;
- assert.equal(msg, modifiedMsg);
- done();
- });
- });
- });
-
- suite('single changes revert', () => {
- let navigateToSearchQueryStub;
- setup(() => {
- getResponseObjectStub
- .returns(Promise.resolve({revert_changes: [
- {change_id: 12345},
- ]}));
- navigateToSearchQueryStub = sinon.stub(GerritNav,
- 'navigateToSearchQuery');
- });
-
- test('revert submission single change', done => {
- element._send('POST', {message: 'Revert submission'},
- '/revert_submission', false, cleanup).then(res => {
- element._handleResponse({__key: 'revert_submission'}, {}).
- then(() => {
- assert.isTrue(navigateToSearchQueryStub.called);
- done();
- });
- });
- });
- });
-
- suite('multiple changes revert', () => {
- let showActionDialogStub;
- let navigateToSearchQueryStub;
- setup(() => {
- getResponseObjectStub
- .returns(Promise.resolve({revert_changes: [
- {change_id: 12345, topic: 'T'},
- {change_id: 23456, topic: 'T'},
- ]}));
- showActionDialogStub = sinon.stub(element, '_showActionDialog');
- navigateToSearchQueryStub = sinon.stub(GerritNav,
- 'navigateToSearchQuery');
- });
-
- test('revert submission multiple change', done => {
- element._send('POST', {message: 'Revert submission'},
- '/revert_submission', false, cleanup).then(res => {
- element._handleResponse({__key: 'revert_submission'}, {}).then(
- () => {
- assert.isFalse(showActionDialogStub.called);
- assert.isTrue(navigateToSearchQueryStub.calledWith(
- 'topic: T'));
- done();
- });
- });
- });
- });
-
- test('revision action', done => {
- element
- ._send('DELETE', payload, '/endpoint', true, cleanup)
- .then(() => {
- assert.isFalse(onShowError.called);
- assert.isTrue(cleanup.calledOnce);
- assert.isTrue(sendStub.calledWith(42, 'DELETE', '/endpoint',
- 12, payload));
- done();
- });
- });
- });
-
- suite('failure modes', () => {
- test('non-latest', () => {
- stubRestApi('getChangeDetail')
- .returns(Promise.resolve({
- ...createChange(),
- // new patchset was uploaded
- revisions: createRevisions(element.latestPatchNum + 1),
- messages: createChangeMessages(1),
- }));
- const sendStub = stubRestApi(
- 'executeChangeAction');
-
- return element._send('DELETE', payload, '/endpoint', true, cleanup)
- .then(() => {
- assert.isTrue(onShowAlert.calledOnce);
- assert.isFalse(onShowError.called);
- assert.isTrue(cleanup.calledOnce);
- assert.isFalse(sendStub.called);
- });
- });
-
- test('send fails', () => {
- stubRestApi('getChangeDetail')
- .returns(Promise.resolve({
- ...createChange(),
- // element has latest info
- revisions: createRevisions(element.latestPatchNum),
- messages: createChangeMessages(1),
- }));
- const sendStub = stubRestApi(
- 'executeChangeAction').callsFake(
- (num, method, patchNum, endpoint, payload, onErr) => {
- onErr();
- return Promise.resolve(null);
- });
- const handleErrorStub = sinon.stub(element, '_handleResponseError');
-
- return element._send('DELETE', payload, '/endpoint', true, cleanup)
- .then(() => {
- assert.isFalse(onShowError.called);
- assert.isTrue(cleanup.called);
- assert.isTrue(sendStub.calledOnce);
- assert.isTrue(handleErrorStub.called);
- });
- });
- });
- });
-
- test('_handleAction reports', () => {
- sinon.stub(element, '_fireAction');
- element.actions = {
- key: {
- __key: 'key',
- __type: 'type',
- },
- };
-
- const reportStub = sinon.stub(element.reporting, 'reportInteraction');
- element._handleAction('type', 'key');
- assert.isTrue(reportStub.called);
- assert.equal(reportStub.lastCall.args[0], 'type-key');
- });
- });
-
- suite('getChangeRevisionActions returns only some actions', () => {
- let element;
-
- let changeRevisionActions;
-
- setup(() => {
- stubRestApi('getChangeRevisionActions').returns(
- Promise.resolve(changeRevisionActions));
- stubRestApi('send').returns(Promise.reject(new Error('error')));
- stubRestApi('getProjectConfig').returns(Promise.resolve({}));
-
- sinon.stub(getPluginLoader(), 'awaitPluginsLoaded')
- .returns(Promise.resolve());
-
- element = basicFixture.instantiate();
- // getChangeRevisionActions is not called without
- // set the following properties
- element.change = {};
- element.changeNum = '42';
- element.latestPatchNum = '2';
-
- stubRestApi('getRepoBranches').returns(Promise.resolve([]));
- return element.reload();
- });
-
- test('confirmSubmitDialog and confirmRebase properties are changed', () => {
- changeRevisionActions = {};
- element.reload();
- assert.strictEqual(element.$.confirmSubmitDialog.action, null);
- assert.strictEqual(element.$.confirmRebase.rebaseOnCurrent, null);
- });
-
- test('_computeRebaseOnCurrent', () => {
- const rebaseAction = {
- enabled: true,
- label: 'Rebase',
- method: 'POST',
- title: 'Rebase onto tip of branch or parent change',
- };
-
- // When rebase is enabled initially, rebaseOnCurrent should be set to
- // true.
- assert.isTrue(element._computeRebaseOnCurrent(rebaseAction));
-
- delete rebaseAction.enabled;
-
- // When rebase is not enabled initially, rebaseOnCurrent should be set to
- // false.
- assert.isFalse(element._computeRebaseOnCurrent(rebaseAction));
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
new file mode 100644
index 0000000..6321e03
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
@@ -0,0 +1,2600 @@
+/**
+ * @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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-change-actions';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
+import {
+ createAccountWithId,
+ createApproval,
+ createChange,
+ createChangeConfig,
+ createChangeMessages,
+ createChangeViewChange,
+ createRevision,
+ createRevisions,
+ createServerInfo,
+} from '../../../test/test-data-generators';
+import {ChangeStatus, HttpMethod} from '../../../constants/constants';
+import {
+ query,
+ queryAll,
+ queryAndAssert,
+ stubRestApi,
+} from '../../../test/test-utils';
+import {assertUIActionInfo, GrChangeActions} from './gr-change-actions';
+import {
+ AccountId,
+ ActionInfo,
+ ActionNameToActionInfoMap,
+ BranchName,
+ ChangeId,
+ ChangeSubmissionId,
+ CommitId,
+ NumericChangeId,
+ PatchSetNum,
+ RepoName,
+ ReviewInput,
+ TopicName,
+} from '../../../types/common';
+import {ActionType} from '../../../api/change-actions';
+import {tap} from '@polymer/iron-test-helpers/mock-interactions';
+import {SinonFakeTimers} from 'sinon/pkg/sinon-esm';
+import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea';
+import {GrButton} from '../../shared/gr-button/gr-button';
+import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
+import {UIActionInfo} from '../../shared/gr-js-api-interface/gr-change-actions-js-api';
+import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
+import {appContext} from '../../../services/app-context';
+
+const basicFixture = fixtureFromElement('gr-change-actions');
+
+// TODO(dhruvsri): remove use of _populateRevertMessage as it's private
+suite('gr-change-actions tests', () => {
+ let element: GrChangeActions;
+
+ suite('basic tests', () => {
+ setup(() => {
+ stubRestApi('getChangeRevisionActions').returns(
+ Promise.resolve({
+ cherrypick: {
+ method: HttpMethod.POST,
+ label: 'Cherry Pick',
+ title: 'Cherry pick change to a different branch',
+ enabled: true,
+ },
+ rebase: {
+ method: HttpMethod.POST,
+ label: 'Rebase',
+ title: 'Rebase onto tip of branch or parent change',
+ enabled: true,
+ },
+ submit: {
+ method: HttpMethod.POST,
+ label: 'Submit',
+ title: 'Submit patch set 2 into master',
+ enabled: true,
+ },
+ revert_submission: {
+ method: HttpMethod.POST,
+ label: 'Revert submission',
+ title: 'Revert this submission',
+ enabled: true,
+ },
+ })
+ );
+ stubRestApi('send').callsFake((method, url) => {
+ if (method !== 'POST') {
+ return Promise.reject(new Error('bad method'));
+ }
+ if (url === '/changes/test~42/revisions/2/submit') {
+ return Promise.resolve({
+ ...new Response(),
+ ok: true,
+ text() {
+ return Promise.resolve(")]}'\n{}");
+ },
+ });
+ } else if (url === '/changes/test~42/revisions/2/rebase') {
+ return Promise.resolve({
+ ...new Response(),
+ ok: true,
+ text() {
+ return Promise.resolve(")]}'\n{}");
+ },
+ });
+ }
+ return Promise.reject(new Error('bad url'));
+ });
+
+ sinon
+ .stub(getPluginLoader(), 'awaitPluginsLoaded')
+ .returns(Promise.resolve());
+
+ element = basicFixture.instantiate();
+ element.change = createChangeViewChange();
+ element.changeNum = 42 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+ element.actions = {
+ '/': {
+ method: HttpMethod.DELETE,
+ label: 'Delete Change',
+ title: 'Delete change X_X',
+ enabled: true,
+ },
+ };
+ element.account = {
+ _account_id: 123 as AccountId,
+ };
+ stubRestApi('getRepoBranches').returns(Promise.resolve([]));
+
+ return element.reload();
+ });
+
+ test('show-revision-actions event should fire', done => {
+ const spy = sinon.spy(element, '_sendShowRevisionActions');
+ element.reload();
+ flush(() => {
+ assert.isTrue(spy.called);
+ done();
+ });
+ });
+
+ test('primary and secondary actions split properly', () => {
+ // Submit should be the only primary action.
+ assert.equal(element._topLevelPrimaryActions!.length, 1);
+ assert.equal(element._topLevelPrimaryActions![0].label, 'Submit');
+ assert.equal(
+ element._topLevelSecondaryActions!.length,
+ element._topLevelActions!.length - 1
+ );
+ });
+
+ test('revert submission action is skipped', () => {
+ assert.equal(
+ element._allActionValues.filter(action => action.__key === 'submit')
+ .length,
+ 1
+ );
+ assert.equal(
+ element._allActionValues.filter(
+ action => action.__key === 'revert_submission'
+ ).length,
+ 0
+ );
+ });
+
+ test('_shouldHideActions', () => {
+ assert.isTrue(element._shouldHideActions(undefined, true));
+ assert.isTrue(
+ element._shouldHideActions(
+ {base: [] as UIActionInfo[]} as PolymerDeepPropertyChange<
+ UIActionInfo[],
+ UIActionInfo[]
+ >,
+ false
+ )
+ );
+ assert.isFalse(
+ element._shouldHideActions(
+ {
+ base: [{__key: 'test'}] as UIActionInfo[],
+ } as PolymerDeepPropertyChange<UIActionInfo[], UIActionInfo[]>,
+ false
+ )
+ );
+ });
+
+ test('plugin revision actions', done => {
+ const stub = stubRestApi('getChangeActionURL').returns(
+ Promise.resolve('the-url')
+ );
+ element.revisionActions = {
+ 'plugin~action': {},
+ };
+ assert.isOk(element.revisionActions['plugin~action']);
+ flush(() => {
+ assert.isTrue(
+ stub.calledWith(
+ element.changeNum,
+ element.latestPatchNum,
+ '/plugin~action'
+ )
+ );
+ assert.equal(
+ (element.revisionActions['plugin~action'] as UIActionInfo)!.__url,
+ 'the-url'
+ );
+ done();
+ });
+ });
+
+ test('plugin change actions', async () => {
+ const stub = stubRestApi('getChangeActionURL').returns(
+ Promise.resolve('the-url')
+ );
+ element.actions = {
+ 'plugin~action': {},
+ };
+ assert.isOk(element.actions['plugin~action']);
+ await flush();
+ assert.isTrue(
+ stub.calledWith(element.changeNum, undefined, '/plugin~action')
+ );
+ assert.equal(
+ (element.actions['plugin~action'] as UIActionInfo)!.__url,
+ 'the-url'
+ );
+ });
+
+ test('not supported actions are filtered out', () => {
+ element.revisionActions = {followup: {}};
+ assert.equal(
+ element.querySelectorAll(
+ 'section gr-button[data-action-type="revision"]'
+ ).length,
+ 0
+ );
+ });
+
+ test('getActionDetails', () => {
+ element.revisionActions = {
+ 'plugin~action': {},
+ ...element.revisionActions,
+ };
+ assert.isUndefined(element.getActionDetails('rubbish'));
+ assert.strictEqual(
+ element.revisionActions['plugin~action'],
+ element.getActionDetails('plugin~action')
+ );
+ assert.strictEqual(
+ element.revisionActions['rebase'],
+ element.getActionDetails('rebase')
+ );
+ });
+
+ test('hide revision action', done => {
+ flush(() => {
+ const buttonEl = queryAndAssert(element, '[data-action-key="submit"]');
+ assert.isOk(buttonEl);
+ element.setActionHidden(
+ element.ActionType.REVISION,
+ element.RevisionActions.SUBMIT,
+ true
+ );
+ assert.lengthOf(element._hiddenActions, 1);
+ element.setActionHidden(
+ element.ActionType.REVISION,
+ element.RevisionActions.SUBMIT,
+ true
+ );
+ assert.lengthOf(element._hiddenActions, 1);
+ flush(() => {
+ const buttonEl = element.shadowRoot?.querySelector(
+ '[data-action-key="submit"]'
+ );
+ assert.isNotOk(buttonEl);
+
+ element.setActionHidden(
+ element.ActionType.REVISION,
+ element.RevisionActions.SUBMIT,
+ false
+ );
+ flush(() => {
+ const buttonEl = queryAndAssert(
+ element,
+ '[data-action-key="submit"]'
+ );
+ assert.isFalse(buttonEl.hasAttribute('hidden'));
+ done();
+ });
+ });
+ });
+ });
+
+ test('buttons exist', done => {
+ element._loading = false;
+ flush(() => {
+ const buttonEls = queryAll(element, 'gr-button');
+ const menuItems = element.$.moreActions.items;
+
+ // Total button number is one greater than the number of total actions
+ // due to the existence of the overflow menu trigger.
+ assert.equal(
+ buttonEls!.length + menuItems!.length,
+ element._allActionValues.length + 1
+ );
+ assert.isFalse(element.hidden);
+ done();
+ });
+ });
+
+ test('delete buttons have explicit labels', done => {
+ flush(() => {
+ const deleteItems = element.$.moreActions.items!.filter(item =>
+ item.id!.startsWith('delete')
+ );
+ assert.equal(deleteItems.length, 1);
+ assert.equal(deleteItems[0].name, 'Delete change');
+ done();
+ });
+ });
+
+ test('get revision object from change', () => {
+ const revObj = {
+ ...createRevision(),
+ _number: 2 as PatchSetNum,
+ foo: 'bar',
+ };
+ const change = {
+ ...createChangeViewChange(),
+ revisions: {
+ rev1: {...createRevision(), _number: 1 as PatchSetNum},
+ rev2: revObj,
+ },
+ };
+ assert.deepEqual(element._getRevision(change, 2 as PatchSetNum), revObj);
+ });
+
+ test('_actionComparator sort order', () => {
+ const actions = [
+ {label: '123', __type: ActionType.CHANGE, __key: 'review'},
+ {label: 'abc-ro', __type: ActionType.REVISION, __key: 'random'},
+ {label: 'abc', __type: ActionType.CHANGE, __key: 'random'},
+ {label: 'def', __type: ActionType.CHANGE, __key: 'random'},
+ {
+ label: 'def-p',
+ __type: ActionType.CHANGE,
+ __primary: true,
+ __key: 'random',
+ },
+ ];
+
+ const result = actions.slice();
+ result.reverse();
+ result.sort(element._actionComparator.bind(element));
+ assert.deepEqual(result, actions);
+ });
+
+ test('submit change', () => {
+ const showSpy = sinon.spy(element, '_showActionDialog');
+ stubRestApi('getFromProjectLookup').returns(
+ Promise.resolve('test' as RepoName)
+ );
+ sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
+ element.change = {
+ ...createChangeViewChange(),
+ revisions: {
+ rev1: {...createRevision(), _number: 1 as PatchSetNum},
+ rev2: {...createRevision(), _number: 2 as PatchSetNum},
+ },
+ };
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ const submitButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="submit"]'
+ );
+ tap(submitButton);
+
+ flush();
+ assert.isTrue(showSpy.calledWith(element.$.confirmSubmitDialog));
+ });
+
+ test('submit change, tap on icon', done => {
+ sinon.stub(element.$.confirmSubmitDialog, 'resetFocus').callsFake(done);
+ stubRestApi('getFromProjectLookup').returns(
+ Promise.resolve('test' as RepoName)
+ );
+ sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
+ element.change = {
+ ...createChangeViewChange(),
+ revisions: {
+ rev1: {...createRevision(), _number: 1 as PatchSetNum},
+ rev2: {...createRevision(), _number: 2 as PatchSetNum},
+ },
+ };
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ const submitIcon = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="submit"] iron-icon'
+ );
+ tap(submitIcon);
+ });
+
+ test('_handleSubmitConfirm', () => {
+ const fireStub = sinon.stub(element, '_fireAction');
+ sinon.stub(element, '_canSubmitChange').returns(true);
+ element._handleSubmitConfirm();
+ assert.isTrue(fireStub.calledOnce);
+ assert.deepEqual(fireStub.lastCall.args, [
+ '/submit',
+ assertUIActionInfo(element.revisionActions.submit),
+ true,
+ ]);
+ });
+
+ test('_handleSubmitConfirm when not able to submit', () => {
+ const fireStub = sinon.stub(element, '_fireAction');
+ sinon.stub(element, '_canSubmitChange').returns(false);
+ element._handleSubmitConfirm();
+ assert.isFalse(fireStub.called);
+ });
+
+ test('submit change with plugin hook', done => {
+ sinon.stub(element, '_canSubmitChange').callsFake(() => false);
+ const fireActionStub = sinon.stub(element, '_fireAction');
+ flush(() => {
+ const submitButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="submit"]'
+ );
+ tap(submitButton);
+ assert.equal(fireActionStub.callCount, 0);
+
+ done();
+ });
+ });
+
+ test('chain state', () => {
+ assert.equal(element._hasKnownChainState, false);
+ element.hasParent = true;
+ assert.equal(element._hasKnownChainState, true);
+ element.hasParent = false;
+ });
+
+ test('_calculateDisabled', () => {
+ let hasKnownChainState = false;
+ const action = {
+ __key: 'rebase',
+ enabled: true,
+ __type: ActionType.CHANGE,
+ label: 'l',
+ };
+ assert.equal(
+ element._calculateDisabled(action, hasKnownChainState),
+ true
+ );
+
+ action.__key = 'delete';
+ assert.equal(
+ element._calculateDisabled(action, hasKnownChainState),
+ false
+ );
+
+ action.__key = 'rebase';
+ hasKnownChainState = true;
+ assert.equal(
+ element._calculateDisabled(action, hasKnownChainState),
+ false
+ );
+
+ action.enabled = false;
+ assert.equal(
+ element._calculateDisabled(action, hasKnownChainState),
+ false
+ );
+ });
+
+ test('rebase change', done => {
+ const fireActionStub = sinon.stub(element, '_fireAction');
+ const fetchChangesStub = sinon
+ .stub(element.$.confirmRebase, 'fetchRecentChanges')
+ .returns(Promise.resolve([]));
+ element._hasKnownChainState = true;
+ flush(() => {
+ const rebaseButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="rebase"]'
+ );
+ tap(rebaseButton);
+ const rebaseAction = {
+ __key: 'rebase',
+ __type: 'revision',
+ __primary: false,
+ enabled: true,
+ label: 'Rebase',
+ method: HttpMethod.POST,
+ title: 'Rebase onto tip of branch or parent change',
+ };
+ assert.isTrue(fetchChangesStub.called);
+ element._handleRebaseConfirm(
+ new CustomEvent('', {detail: {base: '1234'}})
+ );
+ assert.deepEqual(fireActionStub.lastCall.args, [
+ '/rebase',
+ assertUIActionInfo(rebaseAction),
+ true,
+ {base: '1234'},
+ ]);
+ done();
+ });
+ });
+
+ test('rebase change fires reload event', done => {
+ const eventStub = sinon.stub(element, 'dispatchEvent');
+ element._handleResponse(
+ {__key: 'rebase', __type: ActionType.CHANGE, label: 'l'},
+ new Response()
+ );
+ flush(() => {
+ assert.isTrue(eventStub.called);
+ assert.equal(eventStub.lastCall.args[0].type, 'reload');
+ done();
+ });
+ });
+
+ test("rebase dialog gets recent changes each time it's opened", done => {
+ const fetchChangesStub = sinon
+ .stub(element.$.confirmRebase, 'fetchRecentChanges')
+ .returns(Promise.resolve([]));
+ element._hasKnownChainState = true;
+ const rebaseButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="rebase"]'
+ );
+ tap(rebaseButton);
+ assert.isTrue(fetchChangesStub.calledOnce);
+
+ flush(() => {
+ element.$.confirmRebase.dispatchEvent(
+ new CustomEvent('cancel', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ tap(rebaseButton);
+ assert.isTrue(fetchChangesStub.calledTwice);
+ done();
+ });
+ });
+
+ test('two dialogs are not shown at the same time', async () => {
+ element._hasKnownChainState = true;
+ await flush();
+ const rebaseButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="rebase"]'
+ );
+ tap(rebaseButton);
+ await flush();
+ assert.isFalse(element.$.confirmRebase.hidden);
+ stubRestApi('getChanges').returns(Promise.resolve([]));
+ element._handleCherrypickTap();
+ await flush();
+ assert.isTrue(element.$.confirmRebase.hidden);
+ assert.isFalse(element.$.confirmCherrypick.hidden);
+ });
+
+ test('fullscreen-overlay-opened hides content', () => {
+ const spy = sinon.spy(element, '_handleHideBackgroundContent');
+ element.$.overlay.dispatchEvent(
+ new CustomEvent('fullscreen-overlay-opened', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(spy.called);
+ assert.isTrue(element.$.mainContent.classList.contains('overlayOpen'));
+ });
+
+ test('fullscreen-overlay-closed shows content', () => {
+ const spy = sinon.spy(element, '_handleShowBackgroundContent');
+ element.$.overlay.dispatchEvent(
+ new CustomEvent('fullscreen-overlay-closed', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(spy.called);
+ assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
+ });
+
+ test('_setReviewOnRevert', () => {
+ const review = {labels: {Foo: 1, 'Bar-Baz': -2}};
+ const changeId = 1234 as NumericChangeId;
+ sinon
+ .stub(appContext.jsApiService, 'getReviewPostRevert')
+ .returns(review);
+ const saveStub = stubRestApi('saveChangeReview').returns(
+ Promise.resolve(new Response())
+ );
+ const setReviewOnRevert = element._setReviewOnRevert(changeId) as Promise<
+ undefined | Response
+ >;
+ return setReviewOnRevert.then((_res: Response | undefined) => {
+ assert.isTrue(saveStub.calledOnce);
+ assert.equal(saveStub.lastCall.args[0], changeId);
+ assert.deepEqual(saveStub.lastCall.args[2], review);
+ });
+ });
+
+ suite('change edits', () => {
+ test('disableEdit', () => {
+ element.set('editMode', false);
+ element.set('editPatchsetLoaded', false);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ element.set('disableEdit', true);
+ flush();
+
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="publishEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="rebaseEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="deleteEdit"]')
+ );
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ });
+
+ test('shows confirm dialog for delete edit', () => {
+ element.set('editMode', true);
+ element.set('editPatchsetLoaded', true);
+
+ const fireActionStub = sinon.stub(element, '_fireAction');
+ element._handleDeleteEditTap();
+ assert.isFalse(element.$.confirmDeleteEditDialog.hidden);
+ tap(
+ queryAndAssert(
+ queryAndAssert(element, '#confirmDeleteEditDialog'),
+ 'gr-button[primary]'
+ )
+ );
+ flush();
+
+ assert.equal(fireActionStub.lastCall.args[0], '/edit');
+ });
+
+ test('edit patchset is loaded, needs rebase', () => {
+ element.set('editMode', true);
+ element.set('editPatchsetLoaded', true);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ element.editBasedOnCurrentPatchSet = false;
+ flush();
+
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="publishEdit"]')
+ );
+ assert.isOk(query(element, 'gr-button[data-action-key="rebaseEdit"]'));
+ assert.isOk(query(element, 'gr-button[data-action-key="deleteEdit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ });
+
+ test('edit patchset is loaded, does not need rebase', () => {
+ element.set('editMode', true);
+ element.set('editPatchsetLoaded', true);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ element.editBasedOnCurrentPatchSet = true;
+ flush();
+
+ assert.isOk(query(element, 'gr-button[data-action-key="publishEdit"]'));
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="rebaseEdit"]')
+ );
+ assert.isOk(query(element, 'gr-button[data-action-key="deleteEdit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ });
+
+ test('edit mode is loaded, no edit patchset', () => {
+ element.set('editMode', true);
+ element.set('editPatchsetLoaded', false);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ flush();
+
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="publishEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="rebaseEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="deleteEdit"]')
+ );
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ });
+
+ test('normal patch set', () => {
+ element.set('editMode', false);
+ element.set('editPatchsetLoaded', false);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ flush();
+
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="publishEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="rebaseEdit"]')
+ );
+ assert.isNotOk(
+ query(element, 'gr-button[data-action-key="deleteEdit"]')
+ );
+ assert.isOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isNotOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ });
+
+ test('edit action', done => {
+ element.addEventListener('edit-tap', () => {
+ done();
+ });
+ element.set('editMode', true);
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ flush();
+
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ assert.isOk(query(element, 'gr-button[data-action-key="stopEdit"]'));
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.MERGED,
+ };
+ flush();
+
+ assert.isNotOk(query(element, 'gr-button[data-action-key="edit"]'));
+ element.change = {
+ ...createChangeViewChange(),
+ status: ChangeStatus.NEW,
+ };
+ element.set('editMode', false);
+ flush();
+
+ const editButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="edit"]'
+ );
+ tap(editButton);
+ });
+ });
+
+ suite('cherry-pick', () => {
+ let fireActionStub: sinon.SinonStub;
+
+ setup(() => {
+ fireActionStub = sinon.stub(element, '_fireAction');
+ sinon.stub(window, 'alert');
+ });
+
+ test('works', () => {
+ element._handleCherrypickTap();
+ const action = {
+ __key: 'cherrypick',
+ __type: 'revision',
+ __primary: false,
+ enabled: true,
+ label: 'Cherry pick',
+ method: HttpMethod.POST,
+ title: 'Cherry pick change to a different branch',
+ };
+
+ element._handleCherrypickConfirm();
+ assert.equal(fireActionStub.callCount, 0);
+
+ element.$.confirmCherrypick.branch = 'master' as BranchName;
+ element._handleCherrypickConfirm();
+ assert.equal(fireActionStub.callCount, 0); // Still needs a message.
+
+ // Add attributes that are used to determine the message.
+ element.$.confirmCherrypick.commitMessage = 'foo message';
+ element.$.confirmCherrypick.changeStatus = ChangeStatus.NEW;
+ element.$.confirmCherrypick.commitNum = '123' as CommitId;
+
+ element._handleCherrypickConfirm();
+
+ const autogrowEl = queryAndAssert(
+ element.$.confirmCherrypick,
+ '#messageInput'
+ ) as IronAutogrowTextareaElement;
+ assert.equal(autogrowEl.value, 'foo message');
+
+ assert.deepEqual(fireActionStub.lastCall.args, [
+ '/cherrypick',
+ action,
+ true,
+ {
+ destination: 'master',
+ base: null,
+ message: 'foo message',
+ allow_conflicts: false,
+ },
+ ]);
+ });
+
+ test('cherry pick even with conflicts', () => {
+ element._handleCherrypickTap();
+ const action = {
+ __key: 'cherrypick',
+ __type: 'revision',
+ __primary: false,
+ enabled: true,
+ label: 'Cherry pick',
+ method: HttpMethod.POST,
+ title: 'Cherry pick change to a different branch',
+ };
+
+ element.$.confirmCherrypick.branch = 'master' as BranchName;
+
+ // Add attributes that are used to determine the message.
+ element.$.confirmCherrypick.commitMessage = 'foo message';
+ element.$.confirmCherrypick.changeStatus = ChangeStatus.NEW;
+ element.$.confirmCherrypick.commitNum = '123' as CommitId;
+
+ element._handleCherrypickConflictConfirm();
+
+ assert.deepEqual(fireActionStub.lastCall.args, [
+ '/cherrypick',
+ action,
+ true,
+ {
+ destination: 'master',
+ base: null,
+ message: 'foo message',
+ allow_conflicts: true,
+ },
+ ]);
+ });
+
+ test('branch name cleared when re-open cherrypick', () => {
+ const emptyBranchName = '';
+ element.$.confirmCherrypick.branch = 'master' as BranchName;
+
+ element._handleCherrypickTap();
+ assert.equal(element.$.confirmCherrypick.branch, emptyBranchName);
+ });
+
+ suite('cherry pick topics', () => {
+ const changes = [
+ {
+ ...createChangeViewChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ project: 'A' as RepoName,
+ status: ChangeStatus.MERGED,
+ },
+ {
+ ...createChangeViewChange(),
+ change_id: '23456' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'a'.repeat(100),
+ project: 'B' as RepoName,
+ status: ChangeStatus.NEW,
+ },
+ ];
+ setup(done => {
+ stubRestApi('getChanges').returns(Promise.resolve(changes));
+ element._handleCherrypickTap();
+ flush(() => {
+ const radioButtons = queryAll(
+ element.$.confirmCherrypick,
+ "input[name='cherryPickOptions']"
+ );
+ assert.equal(radioButtons.length, 2);
+ tap(radioButtons[1]);
+ flush(() => {
+ done();
+ });
+ });
+ });
+
+ test('cherry pick topic dialog is rendered', done => {
+ const dialog = element.$.confirmCherrypick;
+ flush(() => {
+ const changesTable = queryAndAssert(dialog, 'table');
+ const headers = Array.from(changesTable.querySelectorAll('th'));
+ const expectedHeadings = [
+ '',
+ 'Change',
+ 'Status',
+ 'Subject',
+ 'Project',
+ 'Progress',
+ '',
+ ];
+ const headings = headers.map(header => header.innerText);
+ assert.equal(headings.length, expectedHeadings.length);
+ for (let i = 0; i < headings.length; i++) {
+ assert.equal(headings[i].trim(), expectedHeadings[i]);
+ }
+ const changeRows = queryAll(changesTable, 'tbody > tr');
+ const change = Array.from(changeRows[0].querySelectorAll('td')).map(
+ e => e.innerText
+ );
+ const expectedChange = [
+ '',
+ '1234567890',
+ 'MERGED',
+ 'random',
+ 'A',
+ 'NOT STARTED',
+ '',
+ ];
+ for (let i = 0; i < change.length; i++) {
+ assert.equal(change[i].trim(), expectedChange[i]);
+ }
+ done();
+ });
+ });
+
+ test('changes with duplicate project show an error', done => {
+ const dialog = element.$.confirmCherrypick;
+ const error = queryAndAssert(
+ dialog,
+ '.error-message'
+ ) as HTMLSpanElement;
+ assert.equal(error.innerText, '');
+ dialog.updateChanges([
+ {
+ ...createChangeViewChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ project: 'A' as RepoName,
+ },
+ {
+ ...createChangeViewChange(),
+ change_id: '23456' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'a'.repeat(100),
+ project: 'A' as RepoName,
+ },
+ ]);
+ flush(() => {
+ assert.equal(
+ error.innerText,
+ 'Two changes cannot be of the same' + ' project'
+ );
+ done();
+ });
+ });
+ });
+ });
+
+ suite('move change', () => {
+ let fireActionStub: sinon.SinonStub;
+
+ setup(() => {
+ fireActionStub = sinon.stub(element, '_fireAction');
+ sinon.stub(window, 'alert');
+ element.actions = {
+ move: {
+ method: HttpMethod.POST,
+ label: 'Move',
+ title: 'Move the change',
+ enabled: true,
+ },
+ };
+ });
+
+ test('works', () => {
+ element._handleMoveTap();
+
+ element._handleMoveConfirm();
+ assert.equal(fireActionStub.callCount, 0);
+
+ element.$.confirmMove.branch = 'master' as BranchName;
+ element._handleMoveConfirm();
+ assert.equal(fireActionStub.callCount, 1);
+ });
+
+ test('branch name cleared when re-open move', () => {
+ const emptyBranchName = '';
+ element.$.confirmMove.branch = 'master' as BranchName;
+
+ element._handleMoveTap();
+ assert.equal(element.$.confirmMove.branch, emptyBranchName);
+ });
+ });
+
+ test('custom actions', done => {
+ // Add a button with the same key as a server-based one to ensure
+ // collisions are taken care of.
+ const key = element.addActionButton(element.ActionType.REVISION, 'Bork!');
+ element.addEventListener(key + '-tap', e => {
+ assert.equal(
+ (e as CustomEvent).detail.node.getAttribute('data-action-key'),
+ key
+ );
+ element.removeActionButton(key);
+ flush(() => {
+ assert.notOk(query(element, '[data-action-key="' + key + '"]'));
+ done();
+ });
+ });
+ flush(() => {
+ tap(queryAndAssert(element, '[data-action-key="' + key + '"]'));
+ });
+ });
+
+ test('_setLoadingOnButtonWithKey top-level', () => {
+ const key = 'rebase';
+ const type = 'revision';
+ const cleanup = element._setLoadingOnButtonWithKey(type, key);
+ assert.equal(element._actionLoadingMessage, 'Rebasing...');
+
+ const button = queryAndAssert(
+ element,
+ '[data-action-key="' + key + '"]'
+ ) as GrButton;
+ assert.isTrue(button.hasAttribute('loading'));
+ assert.isTrue(button.disabled);
+
+ assert.isOk(cleanup);
+ assert.isFunction(cleanup);
+ cleanup();
+
+ assert.isFalse(button.hasAttribute('loading'));
+ assert.isFalse(button.disabled);
+ assert.isNotOk(element._actionLoadingMessage);
+ });
+
+ test('_setLoadingOnButtonWithKey overflow menu', () => {
+ const key = 'cherrypick';
+ const type = 'revision';
+ const cleanup = element._setLoadingOnButtonWithKey(type, key);
+ assert.equal(element._actionLoadingMessage, 'Cherry-picking...');
+ assert.include(element._disabledMenuActions, 'cherrypick');
+ assert.isFunction(cleanup);
+
+ cleanup();
+
+ assert.notOk(element._actionLoadingMessage);
+ assert.notInclude(element._disabledMenuActions, 'cherrypick');
+ });
+
+ suite('abandon change', () => {
+ let alertStub: sinon.SinonStub;
+ let fireActionStub: sinon.SinonStub;
+
+ setup(() => {
+ fireActionStub = sinon.stub(element, '_fireAction');
+ alertStub = sinon.stub(window, 'alert');
+ element.actions = {
+ abandon: {
+ method: HttpMethod.POST,
+ label: 'Abandon',
+ title: 'Abandon the change',
+ enabled: true,
+ },
+ };
+ return element.reload();
+ });
+
+ test('abandon change with message', done => {
+ const newAbandonMsg = 'Test Abandon Message';
+ element.$.confirmAbandonDialog.message = newAbandonMsg;
+ flush(() => {
+ const abandonButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="abandon"]'
+ );
+ tap(abandonButton);
+
+ assert.equal(element.$.confirmAbandonDialog.message, newAbandonMsg);
+ done();
+ });
+ });
+
+ test('abandon change with no message', done => {
+ flush(() => {
+ const abandonButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="abandon"]'
+ );
+ tap(abandonButton);
+
+ assert.isUndefined(element.$.confirmAbandonDialog.message);
+ done();
+ });
+ });
+
+ test('works', () => {
+ element.$.confirmAbandonDialog.message = 'original message';
+ const restoreButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="abandon"]'
+ );
+ tap(restoreButton);
+
+ element.$.confirmAbandonDialog.message = 'foo message';
+ element._handleAbandonDialogConfirm();
+ assert.notOk(alertStub.called);
+
+ const action = {
+ __key: 'abandon',
+ __type: 'change',
+ __primary: false,
+ enabled: true,
+ label: 'Abandon',
+ method: HttpMethod.POST,
+ title: 'Abandon the change',
+ };
+ assert.deepEqual(fireActionStub.lastCall.args, [
+ '/abandon',
+ action,
+ false,
+ {
+ message: 'foo message',
+ },
+ ]);
+ });
+ });
+
+ suite('revert change', () => {
+ let fireActionStub: sinon.SinonStub;
+
+ setup(() => {
+ fireActionStub = sinon.stub(element, '_fireAction');
+ element.commitMessage = 'random commit message';
+ element.change!.current_revision = 'abcdef' as CommitId;
+ element.actions = {
+ revert: {
+ method: HttpMethod.POST,
+ label: 'Revert',
+ title: 'Revert the change',
+ enabled: true,
+ },
+ };
+ return element.reload();
+ });
+
+ test('revert change with plugin hook', done => {
+ const newRevertMsg = 'Modified revert msg';
+ sinon
+ .stub(element.$.confirmRevertDialog, '_modifyRevertMsg')
+ .callsFake(() => newRevertMsg);
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ };
+ stubRestApi('getChanges').returns(
+ Promise.resolve([
+ {
+ ...createChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ },
+ {
+ ...createChange(),
+ change_id: '23456' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'a'.repeat(100),
+ },
+ ])
+ );
+ sinon
+ .stub(
+ element.$.confirmRevertDialog,
+ '_populateRevertSubmissionMessage'
+ )
+ .callsFake(() => 'original msg');
+ flush(() => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ tap(revertButton);
+ flush(() => {
+ assert.equal(element.$.confirmRevertDialog._message, newRevertMsg);
+ done();
+ });
+ });
+ });
+
+ suite('revert change submitted together', () => {
+ let getChangesStub: sinon.SinonStub;
+ setup(() => {
+ element.change = {
+ ...createChangeViewChange(),
+ submission_id: '199 0' as ChangeSubmissionId,
+ current_revision: '2000' as CommitId,
+ };
+ getChangesStub = stubRestApi('getChanges').returns(
+ Promise.resolve([
+ {
+ ...createChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ },
+ {
+ ...createChange(),
+ change_id: '23456' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'a'.repeat(100),
+ },
+ ])
+ );
+ });
+
+ test('confirm revert dialog shows both options', done => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ tap(revertButton);
+ flush(() => {
+ assert.equal(getChangesStub.args[0][1], 'submissionid: "199 0"');
+ const confirmRevertDialog = element.$.confirmRevertDialog;
+ const revertSingleChangeLabel = queryAndAssert(
+ confirmRevertDialog,
+ '.revertSingleChange'
+ ) as HTMLLabelElement;
+ const revertSubmissionLabel = queryAndAssert(
+ confirmRevertDialog,
+ '.revertSubmission'
+ ) as HTMLLabelElement;
+ assert(
+ revertSingleChangeLabel.innerText.trim() ===
+ 'Revert single change'
+ );
+ assert(
+ revertSubmissionLabel.innerText.trim() ===
+ 'Revert entire submission (2 Changes)'
+ );
+ let expectedMsg =
+ 'Revert submission 199 0' +
+ '\n\n' +
+ 'Reason for revert: <INSERT REASONING HERE>' +
+ '\n' +
+ 'Reverted Changes:' +
+ '\n' +
+ '1234567890:random' +
+ '\n' +
+ '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+ '\n';
+ assert.equal(confirmRevertDialog._message, expectedMsg);
+ const radioInputs = queryAll(
+ confirmRevertDialog,
+ 'input[name="revertOptions"]'
+ );
+ tap(radioInputs[0]);
+ flush(() => {
+ expectedMsg =
+ 'Revert "random commit message"\n\nThis reverts ' +
+ 'commit 2000.\n\nReason' +
+ ' for revert: <INSERT REASONING HERE>\n';
+ assert.equal(confirmRevertDialog._message, expectedMsg);
+ done();
+ });
+ });
+ });
+
+ test('submit fails if message is not edited', done => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ const confirmRevertDialog = element.$.confirmRevertDialog;
+ tap(revertButton);
+ const fireStub = sinon.stub(confirmRevertDialog, 'dispatchEvent');
+ flush(() => {
+ const confirmButton = queryAndAssert(
+ queryAndAssert(element.$.confirmRevertDialog, 'gr-dialog'),
+ '#confirm'
+ );
+ tap(confirmButton);
+ flush(() => {
+ assert.isTrue(confirmRevertDialog._showErrorMessage);
+ assert.isFalse(fireStub.called);
+ done();
+ });
+ });
+ });
+
+ test('message modification is retained on switching', done => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ const confirmRevertDialog = element.$.confirmRevertDialog;
+ tap(revertButton);
+ flush(() => {
+ const radioInputs = queryAll(
+ confirmRevertDialog,
+ 'input[name="revertOptions"]'
+ );
+ const revertSubmissionMsg =
+ 'Revert submission 199 0' +
+ '\n\n' +
+ 'Reason for revert: <INSERT REASONING HERE>' +
+ '\n' +
+ 'Reverted Changes:' +
+ '\n' +
+ '1234567890:random' +
+ '\n' +
+ '23456:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+ '\n';
+ const singleChangeMsg =
+ 'Revert "random commit message"\n\nThis reverts ' +
+ 'commit 2000.\n\nReason' +
+ ' for revert: <INSERT REASONING HERE>\n';
+ assert.equal(confirmRevertDialog._message, revertSubmissionMsg);
+ const newRevertMsg = revertSubmissionMsg + 'random';
+ const newSingleChangeMsg = singleChangeMsg + 'random';
+ confirmRevertDialog._message = newRevertMsg;
+ tap(radioInputs[0]);
+ flush(() => {
+ assert.equal(confirmRevertDialog._message, singleChangeMsg);
+ confirmRevertDialog._message = newSingleChangeMsg;
+ tap(radioInputs[1]);
+ flush(() => {
+ assert.equal(confirmRevertDialog._message, newRevertMsg);
+ tap(radioInputs[0]);
+ flush(() => {
+ assert.equal(
+ confirmRevertDialog._message,
+ newSingleChangeMsg
+ );
+ done();
+ });
+ });
+ });
+ });
+ });
+ });
+
+ suite('revert single change', () => {
+ setup(() => {
+ element.change = {
+ ...createChangeViewChange(),
+ submission_id: '199' as ChangeSubmissionId,
+ current_revision: '2000' as CommitId,
+ };
+ stubRestApi('getChanges').returns(
+ Promise.resolve([
+ {
+ ...createChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ },
+ ])
+ );
+ });
+
+ test('submit fails if message is not edited', done => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ const confirmRevertDialog = element.$.confirmRevertDialog;
+ tap(revertButton);
+ const fireStub = sinon.stub(confirmRevertDialog, 'dispatchEvent');
+ flush(() => {
+ const confirmButton = queryAndAssert(
+ queryAndAssert(element.$.confirmRevertDialog, 'gr-dialog'),
+ '#confirm'
+ );
+ tap(confirmButton);
+ flush(() => {
+ assert.isTrue(confirmRevertDialog._showErrorMessage);
+ assert.isFalse(fireStub.called);
+ done();
+ });
+ });
+ });
+
+ test('confirm revert dialog shows no radio button', done => {
+ const revertButton = queryAndAssert(
+ element,
+ 'gr-button[data-action-key="revert"]'
+ );
+ tap(revertButton);
+ flush(() => {
+ const confirmRevertDialog = element.$.confirmRevertDialog;
+ const radioInputs = queryAll(
+ confirmRevertDialog,
+ 'input[name="revertOptions"]'
+ );
+ assert.equal(radioInputs.length, 0);
+ const msg =
+ 'Revert "random commit message"\n\n' +
+ 'This reverts commit 2000.\n\nReason ' +
+ 'for revert: <INSERT REASONING HERE>\n';
+ assert.equal(confirmRevertDialog._message, msg);
+ const editedMsg = msg + 'hello';
+ confirmRevertDialog._message += 'hello';
+ const confirmButton = queryAndAssert(
+ queryAndAssert(element.$.confirmRevertDialog, 'gr-dialog'),
+ '#confirm'
+ );
+ tap(confirmButton);
+ flush(() => {
+ assert.equal(fireActionStub.getCall(0).args[0], '/revert');
+ assert.equal(fireActionStub.getCall(0).args[1].__key, 'revert');
+ assert.equal(
+ fireActionStub.getCall(0).args[3].message,
+ editedMsg
+ );
+ done();
+ });
+ });
+ });
+ });
+ });
+
+ suite('mark change private', () => {
+ setup(() => {
+ const privateAction = {
+ __key: 'private',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.POST,
+ label: 'Mark private',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ private: privateAction,
+ };
+
+ element.change!.is_private = false;
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ return element.reload();
+ });
+
+ test(
+ 'make sure the mark private change button is not outside of the ' +
+ 'overflow menu',
+ done => {
+ flush(() => {
+ assert.isNotOk(query(element, '[data-action-key="private"]'));
+ done();
+ });
+ }
+ );
+
+ test('private change', done => {
+ flush(() => {
+ assert.isOk(
+ query(element.$.moreActions, 'span[data-id="private-change"]')
+ );
+ element.setActionOverflow(ActionType.CHANGE, 'private', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="private"]'));
+ assert.isNotOk(
+ query(element.$.moreActions, 'span[data-id="private-change"]')
+ );
+ done();
+ });
+ });
+ });
+
+ suite('unmark private change', () => {
+ setup(() => {
+ const unmarkPrivateAction = {
+ __key: 'private.delete',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.POST,
+ label: 'Unmark private',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ 'private.delete': unmarkPrivateAction,
+ };
+
+ element.change!.is_private = true;
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ return element.reload();
+ });
+
+ test(
+ 'make sure the unmark private change button is not outside of the ' +
+ 'overflow menu',
+ done => {
+ flush(() => {
+ assert.isNotOk(
+ query(element, '[data-action-key="private.delete"]')
+ );
+ done();
+ });
+ }
+ );
+
+ test('unmark the private change', done => {
+ flush(() => {
+ assert.isOk(
+ query(
+ element.$.moreActions,
+ 'span[data-id="private.delete-change"]'
+ )
+ );
+ element.setActionOverflow(ActionType.CHANGE, 'private.delete', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="private.delete"]'));
+ assert.isNotOk(
+ query(
+ element.$.moreActions,
+ 'span[data-id="private.delete-change"]'
+ )
+ );
+ done();
+ });
+ });
+ });
+
+ suite('delete change', () => {
+ let fireActionStub: sinon.SinonStub;
+ let deleteAction: ActionInfo;
+
+ setup(() => {
+ fireActionStub = sinon.stub(element, '_fireAction');
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ };
+ deleteAction = {
+ method: HttpMethod.DELETE,
+ label: 'Delete Change',
+ title: 'Delete change X_X',
+ enabled: true,
+ };
+ element.actions = {
+ '/': deleteAction,
+ };
+ });
+
+ test('does not delete on action', () => {
+ element._handleDeleteTap();
+ assert.isFalse(fireActionStub.called);
+ });
+
+ test('shows confirm dialog', () => {
+ element._handleDeleteTap();
+ assert.isFalse(
+ (queryAndAssert(element, '#confirmDeleteDialog') as GrDialog).hidden
+ );
+ tap(
+ queryAndAssert(
+ queryAndAssert(element, '#confirmDeleteDialog'),
+ 'gr-button[primary]'
+ )
+ );
+ flush();
+ assert.isTrue(fireActionStub.calledWith('/', deleteAction, false));
+ });
+
+ test('hides delete confirm on cancel', () => {
+ element._handleDeleteTap();
+ tap(
+ queryAndAssert(
+ queryAndAssert(element, '#confirmDeleteDialog'),
+ 'gr-button:not([primary])'
+ )
+ );
+ flush();
+ assert.isTrue(
+ (queryAndAssert(element, '#confirmDeleteDialog') as GrDialog).hidden
+ );
+ assert.isFalse(fireActionStub.called);
+ });
+ });
+
+ suite('ignore change', () => {
+ setup(done => {
+ sinon.stub(element, '_fireAction');
+
+ const IgnoreAction = {
+ __key: 'ignore',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.PUT,
+ label: 'Ignore',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ ignore: IgnoreAction,
+ };
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ element.reload().then(() => {
+ flush(done);
+ });
+ });
+
+ test('make sure the ignore button is not outside of the overflow menu', () => {
+ assert.isNotOk(query(element, '[data-action-key="ignore"]'));
+ });
+
+ test('ignoring change', () => {
+ queryAndAssert(element.$.moreActions, 'span[data-id="ignore-change"]');
+ element.setActionOverflow(ActionType.CHANGE, 'ignore', false);
+ flush();
+ queryAndAssert(element, '[data-action-key="ignore"]');
+ assert.isNotOk(
+ query(element.$.moreActions, 'span[data-id="ignore-change"]')
+ );
+ });
+ });
+
+ suite('unignore change', () => {
+ setup(done => {
+ sinon.stub(element, '_fireAction');
+
+ const UnignoreAction = {
+ __key: 'unignore',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.PUT,
+ label: 'Unignore',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ unignore: UnignoreAction,
+ };
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ element.reload().then(() => {
+ flush(done);
+ });
+ });
+
+ test('unignore button is not outside of the overflow menu', () => {
+ assert.isNotOk(query(element, '[data-action-key="unignore"]'));
+ });
+
+ test('unignoring change', () => {
+ assert.isOk(
+ query(element.$.moreActions, 'span[data-id="unignore-change"]')
+ );
+ element.setActionOverflow(ActionType.CHANGE, 'unignore', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="unignore"]'));
+ assert.isNotOk(
+ query(element.$.moreActions, 'span[data-id="unignore-change"]')
+ );
+ });
+ });
+
+ suite('reviewed change', () => {
+ setup(done => {
+ sinon.stub(element, '_fireAction');
+
+ const ReviewedAction = {
+ __key: 'reviewed',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.PUT,
+ label: 'Mark reviewed',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ reviewed: ReviewedAction,
+ };
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ element.reload().then(() => {
+ flush(done);
+ });
+ });
+
+ test('action is enabled', () => {
+ assert.equal(
+ element._allActionValues.filter(action => action.__key === 'reviewed')
+ .length,
+ 1
+ );
+ });
+
+ test('action is skipped when attention set is enabled', () => {
+ element._config = {
+ ...createServerInfo(),
+ change: {...createChangeConfig(), enable_attention_set: true},
+ };
+ assert.equal(
+ element._allActionValues.filter(action => action.__key === 'reviewed')
+ .length,
+ 0
+ );
+ });
+
+ test('make sure the reviewed button is not outside of the overflow menu', () => {
+ assert.isNotOk(query(element, '[data-action-key="reviewed"]'));
+ });
+
+ test('reviewing change', () => {
+ assert.isOk(
+ query(element.$.moreActions, 'span[data-id="reviewed-change"]')
+ );
+ element.setActionOverflow(ActionType.CHANGE, 'reviewed', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="reviewed"]'));
+ assert.isNotOk(
+ query(element.$.moreActions, 'span[data-id="reviewed-change"]')
+ );
+ });
+ });
+
+ suite('unreviewed change', () => {
+ setup(done => {
+ sinon.stub(element, '_fireAction');
+
+ const UnreviewedAction = {
+ __key: 'unreviewed',
+ __type: 'change',
+ __primary: false,
+ method: HttpMethod.PUT,
+ label: 'Mark unreviewed',
+ title: 'Working...',
+ enabled: true,
+ };
+
+ element.actions = {
+ unreviewed: UnreviewedAction,
+ };
+
+ element.changeNum = 2 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ element.reload().then(() => {
+ flush(done);
+ });
+ });
+
+ test('unreviewed button not outside of the overflow menu', () => {
+ assert.isNotOk(query(element, '[data-action-key="unreviewed"]'));
+ });
+
+ test('unreviewed change', () => {
+ assert.isOk(
+ query(element.$.moreActions, 'span[data-id="unreviewed-change"]')
+ );
+ element.setActionOverflow(ActionType.CHANGE, 'unreviewed', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="unreviewed"]'));
+ assert.isNotOk(
+ query(element.$.moreActions, 'span[data-id="unreviewed-change"]')
+ );
+ });
+ });
+
+ suite('quick approve', () => {
+ setup(() => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {
+ values: {
+ '-1': '',
+ ' 0': '',
+ '+1': '',
+ },
+ },
+ },
+ permitted_labels: {
+ foo: ['-1', ' 0', '+1'],
+ },
+ };
+ flush();
+ });
+
+ test('added when can approve', () => {
+ const approveButton = queryAndAssert(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotNull(approveButton);
+ });
+
+ test('hide quick approve', () => {
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotNull(approveButton);
+ assert.isFalse(element._hideQuickApproveAction);
+
+ // Assert approve button gets removed from list of buttons.
+ element.hideQuickApproveAction();
+ flush();
+ const approveButtonUpdated = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButtonUpdated);
+ assert.isTrue(element._hideQuickApproveAction);
+ });
+
+ test('is first in list of secondary actions', () => {
+ const approveButton = element.$.secondaryActions.querySelector(
+ 'gr-button'
+ );
+ assert.equal(approveButton!.getAttribute('data-label'), 'foo+1');
+ });
+
+ test('not added when change is merged', () => {
+ element.change!.status = ChangeStatus.MERGED;
+ flush(() => {
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+ });
+
+ test('not added when already approved', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {
+ approved: {},
+ values: {},
+ },
+ },
+ permitted_labels: {
+ foo: [' 0', '+1'],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+
+ test('not added when label not permitted', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {values: {}},
+ },
+ permitted_labels: {
+ bar: [],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+
+ test('approves when tapped', () => {
+ const fireActionStub = sinon.stub(element, '_fireAction');
+ tap(queryAndAssert(element, "gr-button[data-action-key='review']"));
+ flush();
+ assert.isTrue(fireActionStub.called);
+ assert.isTrue(fireActionStub.calledWith('/review'));
+ const payload = fireActionStub.lastCall.args[3];
+ assert.deepEqual((payload as ReviewInput).labels, {foo: 1});
+ });
+
+ test('not added when multiple labels are required without code review', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {values: {}},
+ bar: {values: {}},
+ },
+ permitted_labels: {
+ foo: [' 0', '+1'],
+ bar: [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+
+ test('code review shown with multiple missing approval', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {values: {}},
+ bar: {values: {}},
+ 'Code-Review': {
+ approved: {},
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ },
+ },
+ permitted_labels: {
+ foo: [' 0', '+1'],
+ bar: [' 0', '+1', '+2'],
+ 'Code-Review': [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = queryAndAssert(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isOk(approveButton);
+ });
+
+ test('button label for missing approval', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ foo: {
+ values: {
+ ' 0': '',
+ '+1': '',
+ },
+ },
+ bar: {approved: {}, values: {}},
+ },
+ permitted_labels: {
+ foo: [' 0', '+1'],
+ bar: [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = queryAndAssert(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.equal(approveButton.getAttribute('data-label'), 'foo+1');
+ });
+
+ test('no quick approve if score is not maximal for a label', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ bar: {
+ value: 1,
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ },
+ },
+ permitted_labels: {
+ bar: [' 0', '+1'],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+
+ test('approving label with a non-max score', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ bar: {
+ value: 1,
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ },
+ },
+ permitted_labels: {
+ bar: [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = queryAndAssert(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.equal(approveButton.getAttribute('data-label'), 'bar+2');
+ });
+
+ test('added when can approve an already-approved code review label', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ 'Code-Review': {
+ approved: {},
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ },
+ },
+ permitted_labels: {
+ 'Code-Review': [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = queryAndAssert(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotNull(approveButton);
+ });
+
+ test('not added when the user has already approved', () => {
+ const vote = {
+ ...createApproval(),
+ _account_id: 123 as AccountId,
+ name: 'name',
+ value: 2,
+ };
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ labels: {
+ 'Code-Review': {
+ approved: {},
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ all: [vote],
+ },
+ },
+ permitted_labels: {
+ 'Code-Review': [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+
+ test('not added when user owns the change', () => {
+ element.change = {
+ ...createChangeViewChange(),
+ current_revision: 'abc1234' as CommitId,
+ owner: createAccountWithId(123),
+ labels: {
+ 'Code-Review': {
+ approved: {},
+ values: {
+ ' 0': '',
+ '+1': '',
+ '+2': '',
+ },
+ },
+ },
+ permitted_labels: {
+ 'Code-Review': [' 0', '+1', '+2'],
+ },
+ };
+ flush();
+ const approveButton = query(
+ element,
+ "gr-button[data-action-key='review']"
+ );
+ assert.isNotOk(approveButton);
+ });
+ });
+
+ test('adds download revision action', () => {
+ const handler = sinon.stub();
+ element.addEventListener('download-tap', handler);
+ assert.ok(element.revisionActions.download);
+ element._handleDownloadTap();
+ flush();
+
+ assert.isTrue(handler.called);
+ });
+
+ test('changing changeNum or patchNum does not reload', () => {
+ const reloadStub = sinon.stub(element, 'reload');
+ element.changeNum = 123 as NumericChangeId;
+ assert.isFalse(reloadStub.called);
+ element.latestPatchNum = 456 as PatchSetNum;
+ assert.isFalse(reloadStub.called);
+ });
+
+ test('_toSentenceCase', () => {
+ assert.equal(element._toSentenceCase('blah blah'), 'Blah blah');
+ assert.equal(element._toSentenceCase('BLAH BLAH'), 'Blah blah');
+ assert.equal(element._toSentenceCase('b'), 'B');
+ assert.equal(element._toSentenceCase(''), '');
+ assert.equal(element._toSentenceCase('!@#$%^&*()'), '!@#$%^&*()');
+ });
+
+ suite('setActionOverflow', () => {
+ test('move action from overflow', () => {
+ assert.isNotOk(query(element, '[data-action-key="cherrypick"]'));
+ assert.strictEqual(
+ element.$.moreActions!.items![0].id,
+ 'cherrypick-revision'
+ );
+ element.setActionOverflow(ActionType.REVISION, 'cherrypick', false);
+ flush();
+ assert.isOk(query(element, '[data-action-key="cherrypick"]'));
+ assert.notEqual(
+ element.$.moreActions!.items![0].id,
+ 'cherrypick-revision'
+ );
+ });
+
+ test('move action to overflow', () => {
+ assert.isOk(query(element, '[data-action-key="submit"]'));
+ element.setActionOverflow(ActionType.REVISION, 'submit', true);
+ flush();
+ assert.isNotOk(query(element, '[data-action-key="submit"]'));
+ assert.strictEqual(
+ element.$.moreActions.items![3].id,
+ 'submit-revision'
+ );
+ });
+
+ suite('_waitForChangeReachable', () => {
+ let clock: SinonFakeTimers;
+ setup(() => {
+ clock = sinon.useFakeTimers();
+ });
+
+ const makeGetChange = (numTries: number) => () => {
+ if (numTries === 1) {
+ return Promise.resolve({
+ ...createChangeViewChange(),
+ _number: 123 as NumericChangeId,
+ });
+ } else {
+ numTries--;
+ return Promise.resolve(null);
+ }
+ };
+
+ const tickAndFlush = async (repetitions: number) => {
+ for (let i = 1; i <= repetitions; i++) {
+ clock.tick(1000);
+ await flush();
+ }
+ };
+
+ test('succeed', async () => {
+ stubRestApi('getChange').callsFake(makeGetChange(5));
+ const promise = element._waitForChangeReachable(
+ 123 as NumericChangeId
+ );
+ tickAndFlush(5);
+ const success = await promise;
+ assert.isTrue(success);
+ });
+
+ test('fail', async () => {
+ stubRestApi('getChange').callsFake(makeGetChange(6));
+ const promise = element._waitForChangeReachable(
+ 123 as NumericChangeId
+ );
+ tickAndFlush(6);
+ const success = await promise;
+ assert.isFalse(success);
+ });
+ });
+ });
+
+ suite('_send', () => {
+ let cleanup: sinon.SinonStub;
+ const payload = {foo: 'bar'};
+ let onShowError: sinon.SinonStub;
+ let onShowAlert: sinon.SinonStub;
+ let getResponseObjectStub: sinon.SinonStub;
+
+ setup(() => {
+ cleanup = sinon.stub();
+ element.changeNum = 42 as NumericChangeId;
+ element.latestPatchNum = 12 as PatchSetNum;
+ element.change = {
+ ...createChangeViewChange(),
+ revisions: createRevisions(element.latestPatchNum as number),
+ messages: createChangeMessages(1),
+ };
+ element.change!._number = 42 as NumericChangeId;
+
+ onShowError = sinon.stub();
+ element.addEventListener('show-error', onShowError);
+ onShowAlert = sinon.stub();
+ element.addEventListener('show-alert', onShowAlert);
+ });
+
+ suite('happy path', () => {
+ let sendStub: sinon.SinonStub;
+ setup(() => {
+ stubRestApi('getChangeDetail').returns(
+ Promise.resolve({
+ ...createChangeViewChange(),
+ // element has latest info
+ revisions: createRevisions(element.latestPatchNum as number),
+ messages: createChangeMessages(1),
+ })
+ );
+ getResponseObjectStub = stubRestApi('getResponseObject');
+ sendStub = stubRestApi('executeChangeAction').returns(
+ Promise.resolve(new Response())
+ );
+ sinon.stub(GerritNav, 'navigateToChange');
+ });
+
+ test('change action', async () => {
+ await element._send(
+ HttpMethod.DELETE,
+ payload,
+ '/endpoint',
+ false,
+ cleanup,
+ {} as UIActionInfo
+ );
+ assert.isFalse(onShowError.called);
+ assert.isTrue(cleanup.calledOnce);
+ assert.isTrue(
+ sendStub.calledWith(
+ 42,
+ HttpMethod.DELETE,
+ '/endpoint',
+ undefined,
+ payload
+ )
+ );
+ });
+
+ suite('show revert submission dialog', () => {
+ setup(() => {
+ element.change!.submission_id = '199' as ChangeSubmissionId;
+ element.change!.current_revision = '2000' as CommitId;
+ stubRestApi('getChanges').returns(
+ Promise.resolve([
+ {
+ ...createChangeViewChange(),
+ change_id: '12345678901234' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'random',
+ },
+ {
+ ...createChangeViewChange(),
+ change_id: '23456' as ChangeId,
+ topic: 'T' as TopicName,
+ subject: 'a'.repeat(100),
+ },
+ ])
+ );
+ });
+
+ test('revert submission shows submissionId', done => {
+ const expectedMsg =
+ 'Revert submission 199' +
+ '\n\n' +
+ 'Reason for revert: <INSERT REASONING HERE>' +
+ '\n' +
+ 'Reverted Changes:' +
+ '\n' +
+ '1234567890: random' +
+ '\n' +
+ '23456: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' +
+ '\n';
+ const modifiedMsg = expectedMsg + 'abcd';
+ sinon
+ .stub(
+ element.$.confirmRevertSubmissionDialog,
+ '_modifyRevertSubmissionMsg'
+ )
+ .returns(modifiedMsg);
+ element.showRevertSubmissionDialog();
+ flush(() => {
+ const msg = element.$.confirmRevertSubmissionDialog.message;
+ assert.equal(msg, modifiedMsg);
+ done();
+ });
+ });
+ });
+
+ suite('single changes revert', () => {
+ let navigateToSearchQueryStub: sinon.SinonStub;
+ setup(() => {
+ getResponseObjectStub.returns(
+ Promise.resolve({revert_changes: [{change_id: 12345}]})
+ );
+ navigateToSearchQueryStub = sinon.stub(
+ GerritNav,
+ 'navigateToSearchQuery'
+ );
+ });
+
+ test('revert submission single change', done => {
+ element
+ ._send(
+ HttpMethod.POST,
+ {message: 'Revert submission'},
+ '/revert_submission',
+ false,
+ cleanup,
+ {} as UIActionInfo
+ )
+ .then(() => {
+ element
+ ._handleResponse(
+ {
+ __key: 'revert_submission',
+ __type: ActionType.CHANGE,
+ label: 'l',
+ },
+ new Response()
+ )!
+ .then(() => {
+ assert.isTrue(navigateToSearchQueryStub.called);
+ done();
+ });
+ });
+ });
+ });
+
+ suite('multiple changes revert', () => {
+ let showActionDialogStub: sinon.SinonStub;
+ let navigateToSearchQueryStub: sinon.SinonStub;
+ setup(() => {
+ getResponseObjectStub.returns(
+ Promise.resolve({
+ revert_changes: [
+ {change_id: 12345, topic: 'T'},
+ {change_id: 23456, topic: 'T'},
+ ],
+ })
+ );
+ showActionDialogStub = sinon.stub(element, '_showActionDialog');
+ navigateToSearchQueryStub = sinon.stub(
+ GerritNav,
+ 'navigateToSearchQuery'
+ );
+ });
+
+ test('revert submission multiple change', done => {
+ element
+ ._send(
+ HttpMethod.POST,
+ {message: 'Revert submission'},
+ '/revert_submission',
+ false,
+ cleanup,
+ {} as UIActionInfo
+ )
+ .then(() => {
+ element
+ ._handleResponse(
+ {
+ __key: 'revert_submission',
+ __type: ActionType.CHANGE,
+ label: 'l',
+ },
+ new Response()
+ )!
+ .then(() => {
+ assert.isFalse(showActionDialogStub.called);
+ assert.isTrue(
+ navigateToSearchQueryStub.calledWith('topic: T')
+ );
+ done();
+ });
+ });
+ });
+ });
+
+ test('revision action', done => {
+ element
+ ._send(
+ HttpMethod.DELETE,
+ payload,
+ '/endpoint',
+ true,
+ cleanup,
+ {} as UIActionInfo
+ )
+ .then(() => {
+ assert.isFalse(onShowError.called);
+ assert.isTrue(cleanup.calledOnce);
+ assert.isTrue(
+ sendStub.calledWith(42, 'DELETE', '/endpoint', 12, payload)
+ );
+ done();
+ });
+ });
+ });
+
+ suite('failure modes', () => {
+ test('non-latest', () => {
+ stubRestApi('getChangeDetail').returns(
+ Promise.resolve({
+ ...createChangeViewChange(),
+ // new patchset was uploaded
+ revisions: createRevisions(
+ (element.latestPatchNum as number) + 1
+ ),
+ messages: createChangeMessages(1),
+ })
+ );
+ const sendStub = stubRestApi('executeChangeAction');
+
+ return element
+ ._send(
+ HttpMethod.DELETE,
+ payload,
+ '/endpoint',
+ true,
+ cleanup,
+ {} as UIActionInfo
+ )
+ .then(() => {
+ assert.isTrue(onShowAlert.calledOnce);
+ assert.isFalse(onShowError.called);
+ assert.isTrue(cleanup.calledOnce);
+ assert.isFalse(sendStub.called);
+ });
+ });
+
+ test('send fails', () => {
+ stubRestApi('getChangeDetail').returns(
+ Promise.resolve({
+ ...createChangeViewChange(),
+ // element has latest info
+ revisions: createRevisions(element.latestPatchNum as number),
+ messages: createChangeMessages(1),
+ })
+ );
+ const sendStub = stubRestApi('executeChangeAction').callsFake(
+ (_num, _method, _patchNum, _endpoint, _payload, onErr) => {
+ onErr!();
+ return Promise.resolve(undefined);
+ }
+ );
+ const handleErrorStub = sinon.stub(element, '_handleResponseError');
+
+ return element
+ ._send(
+ HttpMethod.DELETE,
+ payload,
+ '/endpoint',
+ true,
+ cleanup,
+ {} as UIActionInfo
+ )
+ .then(() => {
+ assert.isFalse(onShowError.called);
+ assert.isTrue(cleanup.called);
+ assert.isTrue(sendStub.calledOnce);
+ assert.isTrue(handleErrorStub.called);
+ });
+ });
+ });
+ });
+
+ test('_handleAction reports', () => {
+ sinon.stub(element, '_fireAction');
+ sinon.stub(element, '_handleChangeAction');
+
+ const reportStub = sinon.stub(element.reporting, 'reportInteraction');
+ element._handleAction(ActionType.CHANGE, 'key');
+ assert.isTrue(reportStub.called);
+ assert.equal(reportStub.lastCall.args[0], 'change-key');
+ });
+ });
+
+ suite('getChangeRevisionActions returns only some actions', () => {
+ let element: GrChangeActions;
+
+ let changeRevisionActions: ActionNameToActionInfoMap = {};
+
+ setup(() => {
+ stubRestApi('getChangeRevisionActions').returns(
+ Promise.resolve(changeRevisionActions)
+ );
+ stubRestApi('send').returns(Promise.reject(new Error('error')));
+
+ sinon
+ .stub(getPluginLoader(), 'awaitPluginsLoaded')
+ .returns(Promise.resolve());
+
+ element = basicFixture.instantiate();
+ // getChangeRevisionActions is not called without
+ // set the following properties
+ element.change = createChangeViewChange();
+ element.changeNum = 42 as NumericChangeId;
+ element.latestPatchNum = 2 as PatchSetNum;
+
+ stubRestApi('getRepoBranches').returns(Promise.resolve([]));
+ return element.reload();
+ });
+
+ test('confirmSubmitDialog and confirmRebase properties are changed', () => {
+ changeRevisionActions = {};
+ element.reload();
+ assert.strictEqual(element.$.confirmSubmitDialog.action, null);
+ assert.strictEqual(element.$.confirmRebase.rebaseOnCurrent, null);
+ });
+
+ test('_computeRebaseOnCurrent', () => {
+ const rebaseAction = {
+ enabled: true,
+ label: 'Rebase',
+ method: HttpMethod.POST,
+ title: 'Rebase onto tip of branch or parent change',
+ };
+
+ // When rebase is enabled initially, rebaseOnCurrent should be set to
+ // true.
+ assert.isTrue(element._computeRebaseOnCurrent(rebaseAction));
+
+ rebaseAction.enabled = false;
+
+ // When rebase is not enabled initially, rebaseOnCurrent should be set to
+ // false.
+ assert.isFalse(element._computeRebaseOnCurrent(rebaseAction));
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.js
deleted file mode 100644
index e71c086..0000000
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.js
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-import './gr-change-metadata.js';
-import {resetPlugins} from '../../../test/test-utils.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const testHtmlPlugin = document.createElement('dom-module');
-testHtmlPlugin.innerHTML = `
- <template>
- <style>
- html {
- --change-metadata-assignee: {
- display: none;
- }
- --change-metadata-label-status: {
- display: none;
- }
- --change-metadata-strategy: {
- display: none;
- }
- --change-metadata-topic: {
- display: none;
- }
- }
- </style>
- </template>
- `;
-testHtmlPlugin.register('my-plugin-style');
-
-const basicFixture = fixtureFromTemplate(
- html`<gr-change-metadata mutable="true"></gr-change-metadata>`
-);
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-change-metadata integration tests', () => {
- let element;
-
- const sectionSelectors = [
- 'section.strategy',
- 'section.topic',
- ];
-
- const labels = {
- CI: {
- all: [
- {value: 1, name: 'user 2', _account_id: 1},
- {value: 2, name: 'user '},
- ],
- values: {
- ' 0': 'Don\'t submit as-is',
- '+1': 'No score',
- '+2': 'Looks good to me',
- },
- },
- };
-
- const getStyle = function(selector, name) {
- return window.getComputedStyle(
- element.root.querySelector(selector))[name];
- };
-
- function createElement() {
- const element = basicFixture.instantiate();
- element.change = {labels, status: 'NEW'};
- element.revision = {};
- return element;
- }
-
- setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('getLoggedIn').returns(Promise.resolve(false));
- stubRestApi('deleteVote').returns(Promise.resolve({ok: true}));
- });
-
- teardown(() => {
- resetPlugins();
- });
-
- suite('by default', () => {
- setup(done => {
- element = createElement();
- flush(done);
- });
-
- for (const sectionSelector of sectionSelectors) {
- test(sectionSelector + ' does not have display: none', () => {
- assert.notEqual(getStyle(sectionSelector, 'display'), 'none');
- });
- }
- });
-
- suite('with plugin style', () => {
- setup(done => {
- resetPlugins();
- pluginApi.install(plugin => {
- plugin.registerStyleModule('change-metadata', 'my-plugin-style');
- }, undefined, 'http://test.com/plugins/style.js');
- element = createElement();
- getPluginLoader().loadPlugins([]);
- getPluginLoader().awaitPluginsLoaded()
- .then(() => {
- flush(done);
- });
- });
-
- teardown(() => {
- document.body.querySelectorAll('custom-style')
- .forEach(style => style.remove());
- });
-
- for (const sectionSelector of sectionSelectors) {
- test('section.strategy may have display: none', () => {
- assert.equal(getStyle(sectionSelector, 'display'), 'none');
- });
- }
- });
-
- suite('label updates', () => {
- let plugin;
-
- setup(() => {
- pluginApi.install(p => {
- plugin = p;
- plugin.registerStyleModule('change-metadata', 'my-plugin-style');
- }, undefined, 'http://test.com/plugins/style.js');
- sinon.stub(getPluginLoader(), 'arePluginsLoaded').returns(true);
- getPluginLoader().loadPlugins([]);
- element = createElement();
- });
-
- teardown(() => {
- document.body.querySelectorAll('custom-style')
- .forEach(style => style.remove());
- });
-
- test('labels changed callback', done => {
- let callCount = 0;
- const labelChangeSpy = sinon.spy(arg => {
- callCount++;
- if (callCount === 1) {
- assert.deepEqual(arg, labels);
- assert.equal(arg.CI.all.length, 2);
- element.set(['change', 'labels'], {
- CI: {
- all: [
- {value: 1, name: 'user 2', _account_id: 1},
- ],
- values: {
- ' 0': 'Don\'t submit as-is',
- '+1': 'No score',
- '+2': 'Looks good to me',
- },
- },
- });
- } else if (callCount === 2) {
- assert.equal(arg.CI.all.length, 1);
- done();
- }
- });
-
- plugin.changeMetadata().onLabelsChanged(labelChangeSpy);
- });
- });
-});
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index 68e2368..e8569ec 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -33,8 +33,6 @@
import '../gr-reviewer-list/gr-reviewer-list';
import '../../shared/gr-account-list/gr-account-list';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-metadata_html';
import {
@@ -67,7 +65,7 @@
ServerInfo,
TopicName,
} from '../../../types/common';
-import {assertNever} from '../../../utils/common-util';
+import {assertNever, unique} from '../../../utils/common-util';
import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
import {GrLinkedChip} from '../../shared/gr-linked-chip/gr-linked-chip';
import {appContext} from '../../../services/app-context';
@@ -78,7 +76,19 @@
DisplayRules,
} from '../../../utils/change-metadata-util';
import {fireEvent} from '../../../utils/event-util';
-import {EditRevisionInfo, ParsedChangeInfo} from '../../../types/types';
+import {
+ EditRevisionInfo,
+ notUndefined,
+ ParsedChangeInfo,
+} from '../../../types/types';
+import {
+ AutocompleteQuery,
+ AutocompleteSuggestion,
+} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {
+ getRevertCommitHash,
+ isRevertCreated,
+} from '../../../utils/message-util';
const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
@@ -118,9 +128,7 @@
}
@customElement('gr-change-metadata')
-export class GrChangeMetadata extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrChangeMetadata extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -206,6 +214,9 @@
@property({type: Boolean})
_isNewChangeSummaryUiEnabled = false;
+ @property({type: Object})
+ queryTopic?: AutocompleteQuery;
+
flagsService = appContext.flagsService;
restApiService = appContext.restApiService;
@@ -218,6 +229,7 @@
this._isNewChangeSummaryUiEnabled = this.flagsService.isEnabled(
KnownExperimentId.NEW_CHANGE_SUMMARY_UI
);
+ this.queryTopic = (input: string) => this._getTopicSuggestions(input);
}
@observe('change.labels')
@@ -284,6 +296,10 @@
return weblinks.length ? weblinks : undefined;
}
+ _isChangeMerged(change?: ParsedChangeInfo) {
+ return change?.status === ChangeStatus.MERGED;
+ }
+
_isAssigneeEnabled(serverConfig?: ServerInfo) {
return !!serverConfig?.change?.enable_assignee;
}
@@ -559,6 +575,32 @@
return 'hideDisplay';
}
+ _computeMergedCommitInfo(
+ current_revision: CommitId,
+ revisions: {[revisionId: string]: RevisionInfo}
+ ) {
+ const rev = revisions[current_revision];
+ if (!rev || !rev.commit) {
+ return {};
+ }
+ // CommitInfo.commit is optional. Set commit in all cases to avoid error
+ // in <gr-commit-info>. @see Issue 5337
+ if (!rev.commit.commit) {
+ rev.commit.commit = current_revision;
+ }
+ return rev.commit;
+ }
+
+ _showRevertCreatedAs(change?: ParsedChangeInfo) {
+ if (!change) return false;
+ return isRevertCreated(change.messages);
+ }
+
+ _computeRevertCommit(change?: ParsedChangeInfo) {
+ if (!change) return undefined;
+ return {commit: getRevertCommitHash(change.messages)};
+ }
+
_computeShowAllLabelText(showAllSections: boolean) {
if (showAllSections) {
return 'Show less';
@@ -678,6 +720,20 @@
provider.init();
return provider;
}
+
+ _getTopicSuggestions(input: string): Promise<AutocompleteSuggestion[]> {
+ return this.restApiService
+ .getChangesWithSimilarTopic(input)
+ .then(response =>
+ (response ?? [])
+ .map(change => change.topic)
+ .filter(notUndefined)
+ .filter(unique)
+ .map(topic => {
+ return {name: topic, value: topic};
+ })
+ );
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 59bf8ad..9db5533 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -246,6 +246,7 @@
change="{{change}}"
mutable="[[_mutable]]"
reviewers-only=""
+ account="[[account]]"
server-config="[[serverConfig]]"
></gr-reviewer-list>
</span>
@@ -259,6 +260,7 @@
change="{{change}}"
mutable="[[_mutable]]"
ccs-only=""
+ account="[[account]]"
server-config="[[serverConfig]]"
></gr-reviewer-list>
</span>
@@ -339,6 +341,34 @@
</ol>
</span>
</section>
+ <template is="dom-if" if="[[_isChangeMerged(change)]]">
+ <section
+ class$="[[_computeDisplayState(_showAllSections, change, _SECTION.MERGED_AS)]]"
+ >
+ <span class="title">Merged As</span>
+ <span class="value">
+ <gr-commit-info
+ change="[[change]]"
+ commit-info="[[_computeMergedCommitInfo(change.current_revision, change.revisions)]]"
+ server-config="[[serverConfig]]"
+ ></gr-commit-info>
+ </span>
+ </section>
+ </template>
+ <template is="dom-if" if="[[_showRevertCreatedAs(change)]]">
+ <section
+ class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REVERT_CREATED_AS)]]"
+ >
+ <span class="title">Revert Created As</span>
+ <span class="value">
+ <gr-commit-info
+ change="[[change]]"
+ commit-info="[[_computeRevertCommit(change)]]"
+ server-config="[[serverConfig]]"
+ ></gr-commit-info>
+ </span>
+ </section>
+ </template>
<section
class$="topic [[_computeDisplayState(_showAllSections, change, _SECTION.TOPIC)]]"
>
@@ -363,6 +393,8 @@
read-only="[[_topicReadOnly]]"
on-changed="_handleTopicChanged"
show-as-edit-pencil="[[_isNewChangeSummaryUiEnabled]]"
+ autocomplete="true"
+ query="[[queryTopic]]"
></gr-editable-label>
</template>
</span>
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
index 59287b2..ab8e404 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
@@ -63,7 +63,7 @@
import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
import {PluginApi} from '../../../api/plugin';
import {GrEndpointDecorator} from '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {stubRestApi} from '../../../test/test-utils';
import {ParsedChangeInfo} from '../../../types/types';
const basicFixture = fixtureFromElement('gr-change-metadata');
@@ -87,6 +87,26 @@
element = basicFixture.instantiate();
});
+ test('_computeMergedCommitInfo', () => {
+ const dummyRevs: {[revisionId: string]: RevisionInfo} = {
+ 1: createRevision(1),
+ 2: createRevision(2),
+ };
+ assert.deepEqual(
+ element._computeMergedCommitInfo('0' as CommitId, dummyRevs),
+ {}
+ );
+ assert.deepEqual(
+ element._computeMergedCommitInfo('1' as CommitId, dummyRevs),
+ dummyRevs[1].commit
+ );
+
+ // Regression test for issue 5337.
+ const commit = element._computeMergedCommitInfo('2' as CommitId, dummyRevs);
+ assert.notDeepEqual(commit, dummyRevs[2]);
+ assert.deepEqual(commit, dummyRevs[2].commit);
+ });
+
test('computed fields', () => {
assert.isFalse(
element._computeHideStrategy({
@@ -938,7 +958,7 @@
.then(el => (hookEl = el as MetadataGrEndpointDecorator));
},
'0.1',
- 'http://some/plugins/url.html'
+ 'http://some/plugins/url.js'
);
getPluginLoader().loadPlugins([]);
flush(() => {
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
index e3fdf7a..56174e5 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
@@ -20,8 +20,6 @@
import '../../shared/gr-label/gr-label';
import '../../shared/gr-label-info/gr-label-info';
import '../../shared/gr-limited-text/gr-limited-text';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-requirements_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -58,9 +56,7 @@
}
@customElement('gr-change-requirements')
-class GrChangeRequirements extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrChangeRequirements extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
index a502949..678fa5c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
@@ -84,6 +84,11 @@
.show-all-button {
float: right;
}
+ .show-all-button iron-icon {
+ color: inherit;
+ --iron-icon-height: 18px;
+ --iron-icon-width: 18px;
+ }
.spacer {
height: var(--spacing-m);
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index 427924e..c4db747 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -21,17 +21,13 @@
import {appContext} from '../../../services/app-context';
import {KnownExperimentId} from '../../../services/flags/flags';
import {
- allRuns$,
- aPluginHasRegistered$,
- someProvidersAreLoading$,
-} from '../../../services/checks/checks-model';
-import {
- Category,
CheckResult,
CheckRun,
- Link,
- RunStatus,
-} from '../../../api/checks';
+ aPluginHasRegistered$,
+ someProvidersAreLoading$,
+ allRunsLatest$,
+} from '../../../services/checks/checks-model';
+import {Category, Link, RunStatus} from '../../../api/checks';
import {fireShowPrimaryTab} from '../../../utils/event-util';
import '../../shared/gr-avatar/gr-avatar';
import {
@@ -101,14 +97,22 @@
}
.summaryChip.warning {
border-color: var(--warning-foreground);
- background-color: var(--warning-background);
+ background: var(--warning-background);
+ }
+ .summaryChip.warning:hover {
+ background: var(--warning-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.summaryChip.warning iron-icon {
color: var(--warning-foreground);
}
.summaryChip.check {
border-color: var(--gray-foreground);
- background-color: var(--gray-background);
+ background: var(--gray-background);
+ }
+ .summaryChip.check:hover {
+ background: var(--gray-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.summaryChip.check iron-icon {
color: var(--gray-foreground);
@@ -120,14 +124,10 @@
render() {
const chipClass = `summaryChip font-small ${this.styleType}`;
const grIcon = this.icon ? `gr-icons:${this.icon}` : '';
- return html`<div
- class="${chipClass}"
- role="button"
- @click="${this.handleClick}"
- >
+ return html`<button class="${chipClass}" @click="${this.handleClick}">
${this.icon && html`<iron-icon icon="${grIcon}"></iron-icon>`}
<slot></slot>
- </div>`;
+ </button>`;
}
private handleClick(e: MouseEvent) {
@@ -184,28 +184,44 @@
.checksChip.error {
color: var(--error-foreground);
border-color: var(--error-foreground);
- background-color: var(--error-background);
+ background: var(--error-background);
+ }
+ .checksChip.error:hover {
+ background: var(--error-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.checksChip.error iron-icon {
color: var(--error-foreground);
}
.checksChip.warning {
border-color: var(--warning-foreground);
- background-color: var(--warning-background);
+ background: var(--warning-background);
+ }
+ .checksChip.warning:hover {
+ background: var(--warning-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.checksChip.warning iron-icon {
color: var(--warning-foreground);
}
.checksChip.info-outline {
border-color: var(--info-foreground);
- background-color: var(--info-background);
+ background: var(--info-background);
+ }
+ .checksChip.info-outline:hover {
+ background: var(--info-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.checksChip.info-outline iron-icon {
color: var(--info-foreground);
}
.checksChip.check-circle-outline {
border-color: var(--success-foreground);
- background-color: var(--success-background);
+ background: var(--success-background);
+ }
+ .checksChip.check-circle-outline:hover {
+ background: var(--success-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.checksChip.check-circle-outline iron-icon {
color: var(--success-foreground);
@@ -214,7 +230,11 @@
}
.checksChip.timelapse {
border-color: var(--gray-foreground);
- background-color: var(--gray-background);
+ background: var(--gray-background);
+ }
+ .checksChip.timelapse:hover {
+ background: var(--gray-background-hover);
+ box-shadow: var(--elevation-level-1);
}
.checksChip.timelapse iron-icon {
color: var(--gray-foreground);
@@ -269,7 +289,7 @@
constructor() {
super();
- this.subscribe('runs', allRuns$);
+ this.subscribe('runs', allRunsLatest$);
this.subscribe('showChecksSummary', aPluginHasRegistered$);
this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
}
@@ -348,9 +368,10 @@
this.detailsQuota -= runs.length;
return runs.map(run => {
const allLinks = resultFilter(run)
- .reduce((links, result) => {
- return links.concat(result.links ?? []);
- }, [] as Link[])
+ .reduce(
+ (links, result) => links.concat(result.links ?? []),
+ [] as Link[]
+ )
.filter(link => link.primary);
const links = allLinks.length === 1 ? allLinks : [];
const text = `${run.checkName}`;
@@ -385,7 +406,7 @@
}
private onChipClick(state: ChecksTabState) {
- fireShowPrimaryTab(this, PrimaryTab.CHECKS, true, {
+ fireShowPrimaryTab(this, PrimaryTab.CHECKS, false, {
checksTab: state,
});
}
@@ -432,7 +453,7 @@
!!draftCount ||
!!countUnresolvedComments}
>
- No Comments</span
+ No comments</span
><gr-summary-chip
styleType=${SummaryChipStyles.WARNING}
category=${CommentTabState.DRAFTS}
@@ -450,7 +471,6 @@
html`<gr-avatar
.account="${account}"
image-size="32"
- aria-label="Account avatar"
></gr-avatar>`
)}
${countUnresolvedComments} unresolved</gr-summary-chip
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index ab1c48f..34839e6 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -42,11 +42,8 @@
import '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
import '../gr-reply-dialog/gr-reply-dialog';
import '../gr-thread-list/gr-thread-list';
-import '../gr-upload-help-dialog/gr-upload-help-dialog';
import '../../checks/gr-checks-tab';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-view_html';
import {
@@ -77,7 +74,7 @@
hasEditPatchsetLoaded,
PatchSet,
} from '../../../utils/patch-set-util';
-import {changeStatuses, changeStatusString} from '../../../utils/change-util';
+import {changeStatuses} from '../../../utils/change-util';
import {EventType as PluginEventType} from '../../../api/plugin';
import {customElement, property, observe} from '@polymer/decorators';
import {GrApplyFixDialog} from '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
@@ -111,6 +108,7 @@
ChangeId,
RelatedChangeAndCommitInfo,
RelatedChangesInfo,
+ BasePatchSetNum,
} from '../../../types/common';
import {DiffPreferencesInfo} from '../../../types/diff';
import {GrReplyDialog, FocusTarget} from '../gr-reply-dialog/gr-reply-dialog';
@@ -156,24 +154,27 @@
SwitchTabEvent,
ThreadListModifiedEvent,
TabState,
+ EventType,
+ CloseFixPreviewEvent,
} from '../../../types/events';
import {GrButton} from '../../shared/gr-button/gr-button';
import {GrMessagesList} from '../gr-messages-list/gr-messages-list';
import {GrThreadList} from '../gr-thread-list/gr-thread-list';
import {
- EventType,
fireAlert,
fireEvent,
firePageError,
fireDialogChange,
+ fireTitleChange,
} from '../../../utils/event-util';
import {KnownExperimentId} from '../../../services/flags/flags';
-import {fireTitleChange} from '../../../utils/event-util';
import {GerritView} from '../../../services/router/router-model';
import {takeUntil} from 'rxjs/operators';
import {aPluginHasRegistered$} from '../../../services/checks/checks-model';
import {Subject} from 'rxjs';
import {GrRelatedChangesListExperimental} from '../gr-related-changes-list-experimental/gr-related-changes-list-experimental';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {Timing} from '../../../constants/reporting';
const CHANGE_ID_ERROR = {
MISMATCH: 'mismatch',
@@ -211,9 +212,6 @@
NEW_MESSAGE: 'There are new messages on this change',
};
-const CHANGE_DATA_TIMING_LABEL = 'ChangeDataLoaded';
-const CHANGE_RELOAD_TIMING_LABEL = 'ChangeReloaded';
-const SEND_REPLY_TIMING_LABEL = 'SendReply';
// Making the tab names more unique in case a plugin adds one with same name
const ROBOT_COMMENTS_LIMIT = 10;
@@ -228,7 +226,6 @@
includedInDialog: GrIncludedInDialog;
downloadOverlay: GrOverlay;
downloadDialog: GrDownloadDialog;
- uploadHelpOverlay: GrOverlay;
replyOverlay: GrOverlay;
replyDialog: GrReplyDialog;
mainContent: HTMLDivElement;
@@ -244,14 +241,8 @@
export type ChangeViewPatchRange = Partial<PatchRange>;
-const DEBOUNCER_REPLY_OVERLAY_REFIT = 'reply-overlay-refit';
-
-const DEBOUNCER_SCROLL = 'scroll';
-
@customElement('gr-change-view')
-export class GrChangeView extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrChangeView extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -459,9 +450,6 @@
@property({type: Boolean})
_replyDisabled = true;
- @property({type: String, computed: '_changeStatusString(_change)'})
- _changeStatus?: string;
-
@property({
type: String,
computed: '_computeChangeStatusChips(_change, _mergeable, _submitEnabled)',
@@ -593,6 +581,10 @@
disconnected$ = new Subject();
+ private replyRefitTask?: DelayedTask;
+
+ private scrollTask?: DelayedTask;
+
/** @override */
ready() {
super.ready();
@@ -604,26 +596,9 @@
);
}
- /** @override */
- connectedCallback() {
- super.connectedCallback();
- this._throttledToggleChangeStar = this._throttleWrap(e =>
- this._handleToggleChangeStar(e as CustomKeyboardEvent)
- );
- }
-
- /** @override */
- disconnectedCallback() {
- this.disconnected$.next();
- super.disconnectedCallback();
- }
-
- /** @override */
- created() {
- super.created();
-
+ constructor() {
+ super();
this.addEventListener('topic-changed', () => this._handleTopicChanged());
-
this.addEventListener(
// When an overlay is opened in a mobile viewport, the overlay has a full
// screen view. When it has a full screen view, we do not want the
@@ -651,8 +626,11 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
+ this._throttledToggleChangeStar = this._throttleWrap(e =>
+ this._handleToggleChangeStar(e as CustomKeyboardEvent)
+ );
this._getServerConfig().then(config => {
this._serverConfig = config;
this._replyDisabled = false;
@@ -699,9 +677,9 @@
this._handleCommitMessageCancel()
);
this.addEventListener('open-fix-preview', e => this._onOpenFixPreview(e));
- this.addEventListener('close-fix-preview', () => this._onCloseFixPreview());
- this.listen(window, 'scroll', '_handleScroll');
- this.listen(document, 'visibilitychange', '_handleVisibilityChange');
+ this.addEventListener('close-fix-preview', e => this._onCloseFixPreview(e));
+ window.addEventListener('scroll', this.handleScroll);
+ document.addEventListener('visibilitychange', this.handleVisibilityChange);
this.addEventListener(EventType.SHOW_PRIMARY_TAB, e =>
this._setActivePrimaryTab(e)
@@ -719,16 +697,20 @@
}
/** @override */
- detached() {
- super.detached();
- this.unlisten(window, 'scroll', '_handleScroll');
- this.unlisten(document, 'visibilitychange', '_handleVisibilityChange');
- this.cancelDebouncer(DEBOUNCER_REPLY_OVERLAY_REFIT);
- this.cancelDebouncer(DEBOUNCER_SCROLL);
+ disconnectedCallback() {
+ this.disconnected$.next();
+ window.removeEventListener('scroll', this.handleScroll);
+ document.removeEventListener(
+ 'visibilitychange',
+ this.handleVisibilityChange
+ );
+ this.replyRefitTask?.cancel();
+ this.scrollTask?.cancel();
if (this._updateCheckTimerHandle) {
this._cancelUpdateCheckTimer();
}
+ super.disconnectedCallback();
}
get messagesList(): GrMessagesList | null {
@@ -739,10 +721,6 @@
return this.shadowRoot!.querySelector<GrThreadList>('gr-thread-list');
}
- _changeStatusString(change: ChangeInfo) {
- return changeStatusString(change);
- }
-
_setDiffViewMode(opt_reset?: boolean) {
if (!opt_reset && this.viewState.diffViewMode) {
return;
@@ -765,8 +743,8 @@
this.$.applyFixDialog.open(e);
}
- _onCloseFixPreview() {
- this._reload();
+ _onCloseFixPreview(e: CloseFixPreviewEvent) {
+ if (e.detail.fixApplied) this._reload();
}
_handleToggleDiffMode(e: CustomKeyboardEvent) {
@@ -797,13 +775,14 @@
activeTabName?: string;
activeTabIndex?: number;
scrollIntoView?: boolean;
- }
+ },
+ src?: string
) {
if (!paperTabs) return;
const {activeTabName, activeTabIndex, scrollIntoView} = activeDetails;
- const tabs = paperTabs.querySelectorAll('paper-tab') as NodeListOf<
- HTMLElement
- >;
+ const tabs = paperTabs.querySelectorAll(
+ 'paper-tab'
+ ) as NodeListOf<HTMLElement>;
let activeIndex = -1;
if (activeTabIndex !== undefined) {
activeIndex = activeTabIndex;
@@ -822,12 +801,12 @@
}
const tabName = tabs[activeIndex].dataset['name'];
if (scrollIntoView) {
- paperTabs.scrollIntoView();
+ paperTabs.scrollIntoView({block: 'center'});
}
if (paperTabs.selected !== activeIndex) {
// paperTabs.selected is undefined during rendering
if (paperTabs.selected !== undefined) {
- this.reporting.reportInteraction('show-tab', {tabName});
+ this.reporting.reportInteraction('show-tab', {tabName, src});
}
paperTabs.selected = activeIndex;
}
@@ -841,11 +820,15 @@
const primaryTabs = this.shadowRoot!.querySelector<PaperTabsElement>(
'#primaryTabs'
);
- const activeTabName = this._setActiveTab(primaryTabs, {
- activeTabName: e.detail.tab,
- activeTabIndex: e.detail.value,
- scrollIntoView: e.detail.scrollIntoView,
- });
+ const activeTabName = this._setActiveTab(
+ primaryTabs,
+ {
+ activeTabName: e.detail.tab,
+ activeTabIndex: e.detail.value,
+ scrollIntoView: e.detail.scrollIntoView,
+ },
+ (e.composedPath()?.[0] as Element | undefined)?.tagName
+ );
if (activeTabName) {
this._activeTabs = [activeTabName, this._activeTabs[1]];
@@ -885,6 +868,21 @@
}
}
+ _onPaperTabClick(e: MouseEvent) {
+ let target = e.target as HTMLElement | null;
+ let tabName: string | undefined;
+ // target can be slot child of papertab, so we search for tabName in parents
+ do {
+ tabName = target?.dataset?.['name'];
+ if (tabName) break;
+ target = target?.parentElement as HTMLElement | null;
+ } while (target);
+ this.reporting.reportInteraction('show-tab', {
+ tabName,
+ src: 'paper-tab-click',
+ });
+ }
+
_handleEditCommitMessage() {
this._editingCommitMessage = true;
this.$.commitMessageEditor.focusTextarea();
@@ -1203,14 +1201,6 @@
this.$.downloadOverlay.close();
}
- _handleOpenUploadHelpDialog() {
- this.$.uploadHelpOverlay.open();
- }
-
- _handleCloseUploadHelpDialog() {
- this.$.uploadHelpOverlay.close();
- }
-
_handleMessageReply(e: CustomEvent<{message: {message: string}}>) {
const msg: string = e.detail.message.message;
const quoteStr =
@@ -1234,7 +1224,7 @@
this.addEventListener(
'change-details-loaded',
() => {
- this.reporting.timeEnd(SEND_REPLY_TIMING_LABEL);
+ this.reporting.timeEnd(Timing.SEND_REPLY);
},
{once: true}
);
@@ -1248,11 +1238,9 @@
_handleReplyAutogrow() {
// If the textarea resizes, we need to re-fit the overlay.
- this.debounce(
- DEBOUNCER_REPLY_OVERLAY_REFIT,
- () => {
- this.$.replyOverlay.refit();
- },
+ this.replyRefitTask = debounce(
+ this.replyRefitTask,
+ () => this.$.replyOverlay.refit(),
REPLY_REFIT_DEBOUNCE_INTERVAL_MS
);
}
@@ -1265,15 +1253,13 @@
this._openReplyDialog(target);
}
- _handleScroll() {
- this.debounce(
- DEBOUNCER_SCROLL,
- () => {
- this.viewState.scrollTop = document.body.scrollTop;
- },
+ readonly handleScroll = () => {
+ this.scrollTask = debounce(
+ this.scrollTask,
+ () => (this.viewState.scrollTop = document.body.scrollTop),
150
);
- }
+ };
_setShownFiles(e: CustomEvent<{length: number}>) {
this._shownFileCount = e.detail.length;
@@ -1386,7 +1372,7 @@
this._sendShowChangeEvent();
- this.async(() => {
+ setTimeout(() => {
if (this.viewState.scrollTop) {
document.documentElement.scrollTop = document.body.scrollTop = this.viewState.scrollTop;
} else {
@@ -1498,10 +1484,10 @@
if (this.viewState.showReplyDialog) {
this._openReplyDialog(this.$.replyDialog.FocusTarget.ANY);
// TODO(kaspern@): Find a better signal for when to call center.
- this.async(() => {
+ setTimeout(() => {
this.$.replyOverlay.center();
}, 100);
- this.async(() => {
+ setTimeout(() => {
this.$.replyOverlay.center();
}, 1000);
this.set('viewState.showReplyDialog', false);
@@ -1586,26 +1572,6 @@
return GerritNav.getUrlForChange(change);
}
- _computeShowCommitInfo(changeStatus: string, current_revision: RevisionInfo) {
- return changeStatus === 'Merged' && current_revision;
- }
-
- _computeMergedCommitInfo(
- current_revision: CommitId,
- revisions: {[revisionId: string]: RevisionInfo}
- ) {
- const rev = revisions[current_revision];
- if (!rev || !rev.commit) {
- return {};
- }
- // CommitInfo.commit is optional. Set commit in all cases to avoid error
- // in <gr-commit-info>. @see Issue 5337
- if (!rev.commit.commit) {
- rev.commit.commit = current_revision;
- }
- return rev.commit;
- }
-
_computeChangeIdClass(displayChangeId: string) {
return displayChangeId === CHANGE_ID_ERROR.MISMATCH ? 'warning' : '';
}
@@ -1772,7 +1738,7 @@
GerritNav.navigateToChange(
this._change,
latestPatchNum,
- this._patchRange.patchNum
+ this._patchRange.patchNum as BasePatchSetNum
);
}
@@ -1902,6 +1868,7 @@
}
_openReplyDialog(section?: FocusTarget) {
+ if (!this._change) return;
this.$.replyOverlay.open().finally(() => {
// the following code should be executed no matter open succeed or not
this._resetReplyOverlayFocusStops();
@@ -2053,7 +2020,7 @@
}
);
}
- return false;
+ return true;
}
);
}
@@ -2204,8 +2171,8 @@
}
this._loading = true;
this._relatedChangesCollapsed = true;
- this.reporting.time(CHANGE_RELOAD_TIMING_LABEL);
- this.reporting.time(CHANGE_DATA_TIMING_LABEL);
+ this.reporting.time(Timing.CHANGE_RELOAD);
+ this.reporting.time(Timing.CHANGE_DATA);
// Array to house all promises related to data requests.
const allDataPromises: Promise<unknown>[] = [];
@@ -2224,16 +2191,17 @@
fireEvent(this, 'change-details-loaded');
})
.then(() => {
- this.reporting.timeEnd(CHANGE_RELOAD_TIMING_LABEL);
+ this.reporting.timeEnd(Timing.CHANGE_RELOAD);
if (isLocationChange) {
this.reporting.changeDisplayed();
}
});
- // Resolves when the project config has loaded.
- const projectConfigLoaded = detailCompletes.then(() =>
- this._getProjectConfig()
- );
+ // Resolves when the project config has successfully loaded.
+ const projectConfigLoaded = detailCompletes.then(success => {
+ if (!success) return Promise.resolve();
+ return this._getProjectConfig();
+ });
allDataPromises.push(projectConfigLoaded);
// Resolves when change comments have loaded (comments, drafts and robot
@@ -2329,7 +2297,7 @@
}
Promise.all(allDataPromises).then(() => {
- this.reporting.timeEnd(CHANGE_DATA_TIMING_LABEL);
+ this.reporting.timeEnd(Timing.CHANGE_DATA);
if (isLocationChange) {
this.reporting.changeFullyLoaded();
}
@@ -2464,7 +2432,7 @@
return false;
}
const MIN_LINES = this._isNewChangeSummaryUiEnabled
- ? 15
+ ? 17
: MIN_LINES_FOR_COMMIT_COLLAPSE;
return commitMessage.split('\n').length >= MIN_LINES;
}
@@ -2597,7 +2565,7 @@
return;
}
- this._updateCheckTimerHandle = this.async(() => {
+ this._updateCheckTimerHandle = window.setTimeout(() => {
assertIsDefined(this._change, '_change');
const change = this._change;
fetchChangeUpdates(change, this.restApiService).then(result => {
@@ -2653,18 +2621,18 @@
_cancelUpdateCheckTimer() {
if (this._updateCheckTimerHandle) {
- this.cancelAsync(this._updateCheckTimerHandle);
+ window.clearTimeout(this._updateCheckTimerHandle);
}
this._updateCheckTimerHandle = null;
}
- _handleVisibilityChange() {
+ private readonly handleVisibilityChange = () => {
if (document.hidden && this._updateCheckTimerHandle) {
this._cancelUpdateCheckTimer();
} else if (!this._updateCheckTimerHandle) {
this._startUpdateCheckTimer();
}
- }
+ };
_handleTopicChanged() {
this.getRelatedChangesList()?.reload();
@@ -2702,9 +2670,9 @@
_handleFileActionTap(e: CustomEvent<{path: string; action: string}>) {
e.preventDefault();
- const controls = this.$.fileListHeader.shadowRoot!.querySelector<
- GrEditControls
- >('#editControls');
+ const controls = this.$.fileListHeader.shadowRoot!.querySelector<GrEditControls>(
+ '#editControls'
+ );
if (!controls) throw new Error('Missing edit controls');
assertIsDefined(this._change, '_change');
if (!this._patchRange)
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index 08c04e8..bb99529 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -149,7 +149,7 @@
overflow-x: hidden;
}
.relatedChanges {
- flex: 1 1 auto;
+ flex: 0 1 auto;
overflow: hidden;
padding: var(--spacing-l) 0;
}
@@ -171,6 +171,9 @@
overflow: hidden;
position: relative; /* for arrowToCurrentChange to have position:absolute and be hidden */
}
+ .emptySpace {
+ flex-grow: 1;
+ }
.commitContainer {
display: flex;
flex-direction: column;
@@ -365,24 +368,12 @@
<div class="changeStatuses">
<template is="dom-repeat" items="[[_changeStatuses]]" as="status">
<gr-change-status
+ change="[[_change]]"
max-width="100"
status="[[status]]"
></gr-change-status>
</template>
</div>
- <div class="statusText">
- <template
- is="dom-if"
- if="[[_computeShowCommitInfo(_changeStatus, _change.current_revision)]]"
- >
- <span class="text"> as </span>
- <gr-commit-info
- change="[[_change]]"
- commit-info="[[_computeMergedCommitInfo(_change.current_revision, _change.revisions)]]"
- server-config="[[_serverConfig]]"
- ></gr-commit-info>
- </template>
- </div>
<gr-change-star
id="changeStar"
change="{{_change}}"
@@ -575,6 +566,7 @@
</div>
</template>
</div>
+ <div class="emptySpace"></div>
</div>
</div>
</div>
@@ -582,8 +574,13 @@
<h2 class="assistive-tech-only">Files and Comments tabs</h2>
<paper-tabs id="primaryTabs" on-selected-changed="_setActivePrimaryTab">
- <paper-tab data-name$="[[_constants.PrimaryTab.FILES]]">Files</paper-tab>
<paper-tab
+ on-click="_onPaperTabClick"
+ data-name$="[[_constants.PrimaryTab.FILES]]"
+ >Files</paper-tab
+ >
+ <paper-tab
+ on-click="_onPaperTabClick"
data-name$="[[_constants.PrimaryTab.COMMENT_THREADS]]"
class="commentThreads"
>
@@ -595,7 +592,9 @@
>
</paper-tab>
<template is="dom-if" if="[[_showChecksTab]]">
- <paper-tab data-name$="[[_constants.PrimaryTab.CHECKS]]"
+ <paper-tab
+ data-name$="[[_constants.PrimaryTab.CHECKS]]"
+ on-click="_onPaperTabClick"
>Checks</paper-tab
>
</template>
@@ -613,7 +612,10 @@
</gr-endpoint-decorator>
</paper-tab>
</template>
- <paper-tab data-name$="[[_constants.PrimaryTab.FINDINGS]]">
+ <paper-tab
+ data-name$="[[_constants.PrimaryTab.FINDINGS]]"
+ on-click="_onPaperTabClick"
+ >
Findings
</paper-tab>
</paper-tabs>
@@ -644,7 +646,6 @@
diff-prefs-disabled="[[_diffPrefsDisabled]]"
on-open-diff-prefs="_handleOpenDiffPrefs"
on-open-download-dialog="_handleOpenDownloadDialog"
- on-open-upload-help-dialog="_handleOpenUploadHelpDialog"
on-open-included-in-dialog="_handleOpenIncludedInDialog"
on-expand-diffs="_expandAllDiffs"
on-collapse-diffs="_collapseAllDiffs"
@@ -790,13 +791,6 @@
on-close="_handleDownloadDialogClose"
></gr-download-dialog>
</gr-overlay>
- <gr-overlay id="uploadHelpOverlay" with-backdrop="">
- <gr-upload-help-dialog
- revision="[[_currentRevision]]"
- target-branch="[[_change.branch]]"
- on-close="_handleCloseUploadHelpDialog"
- ></gr-upload-help-dialog>
- </gr-overlay>
<gr-overlay id="includedInOverlay" with-backdrop="">
<gr-included-in-dialog
id="includedInDialog"
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index ae446cd..d1f9ff0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -38,6 +38,7 @@
import 'lodash/lodash';
import {
stubRestApi,
+ SinonSpyMember,
TestKeyboardShortcutBinder,
} from '../../../test/test-utils';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -59,11 +60,13 @@
getCurrentRevision,
createEditRevision,
createAccountWithIdNameAndEmail,
+ createChangeViewChange,
} from '../../../test/test-data-generators';
import {ChangeViewPatchRange, GrChangeView} from './gr-change-view';
import {
AccountId,
ApprovalInfo,
+ BasePatchSetNum,
ChangeId,
ChangeInfo,
CommitId,
@@ -77,6 +80,7 @@
PatchRange,
PatchSetNum,
RevisionInfo,
+ RevisionPatchSetNum,
RobotId,
Timestamp,
UrlEncodedCommentId,
@@ -87,11 +91,7 @@
} from '@polymer/iron-test-helpers/mock-interactions';
import {GrEditControls} from '../../edit/gr-edit-controls/gr-edit-controls';
import {AppElementChangeViewParams} from '../../gr-app-types';
-import {
- SinonFakeTimers,
- SinonSpy,
- SinonStubbedMember,
-} from 'sinon/pkg/sinon-esm';
+import {SinonFakeTimers, SinonStubbedMember} from 'sinon/pkg/sinon-esm';
import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
import {CustomKeyboardEvent} from '../../../types/events';
import {
@@ -100,7 +100,6 @@
UIDraft,
UIRobot,
} from '../../../utils/comment-util';
-import 'lodash/lodash';
import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
import {GerritView} from '../../../services/router/router-model';
import {ParsedChangeInfo} from '../../../types/types';
@@ -110,15 +109,12 @@
const pluginApi = _testOnly_initGerritPluginApi();
const fixture = fixtureFromElement('gr-change-view');
-type SinonSpyMember<F extends (...args: any) => any> = SinonSpy<
- Parameters<F>,
- ReturnType<F>
->;
-
suite('gr-change-view tests', () => {
let element: GrChangeView;
- let navigateToChangeStub: SinonStubbedMember<typeof GerritNav.navigateToChange>;
+ let navigateToChangeStub: SinonStubbedMember<
+ typeof GerritNav.navigateToChange
+ >;
suiteSetup(() => {
const kb = TestKeyboardShortcutBinder.push();
@@ -190,7 +186,7 @@
patch_set: 2 as PatchSetNum,
},
],
- patchNum: 4 as PatchSetNum,
+ patchNum: 4 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 5,
rootId: 'ecf0b9fa_fe1a5f62' as UrlEncodedCommentId,
@@ -250,7 +246,7 @@
unresolved: true,
},
],
- patchNum: 2 as PatchSetNum,
+ patchNum: 2 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 4,
rootId: '8caddf38_44770ec1' as UrlEncodedCommentId,
@@ -273,7 +269,7 @@
unresolved: true,
},
],
- patchNum: 2 as PatchSetNum,
+ patchNum: 2 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 4,
rootId: 'scaddf38_44770ec1' as UrlEncodedCommentId,
@@ -294,7 +290,7 @@
patch_set: 2 as PatchSetNum,
},
],
- patchNum: 4 as PatchSetNum,
+ patchNum: 4 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 6,
rootId: 'zcf0b9fa_fe1a5f62' as UrlEncodedCommentId,
@@ -318,7 +314,7 @@
robot_id: 'rc1' as RobotId,
},
],
- patchNum: 4 as PatchSetNum,
+ patchNum: 4 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 5,
rootId: 'rc1' as UrlEncodedCommentId,
@@ -356,7 +352,7 @@
unresolved: true,
},
],
- patchNum: 4 as PatchSetNum,
+ patchNum: 4 as RevisionPatchSetNum,
path: '/COMMIT_MSG',
line: 5,
rootId: 'rc2' as UrlEncodedCommentId,
@@ -398,7 +394,7 @@
);
},
'0.1',
- 'http://some/plugins/url.html'
+ 'http://some/plugins/url.js'
);
});
@@ -415,9 +411,9 @@
element._changeNum = 1 as NumericChangeId;
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
- element._change = createChange();
+ element._change = createChangeViewChange();
const getUrlStub = sinon.stub(GerritNav, 'getUrlForChange');
const replaceStateStub = sinon.stub(history, 'replaceState');
element._handleMessageAnchorTap(
@@ -430,12 +426,12 @@
test('_handleDiffAgainstBase', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(10),
};
element._patchRange = {
- patchNum: 3 as PatchSetNum,
- basePatchNum: 1 as PatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
};
sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
element._handleDiffAgainstBase(new CustomEvent('') as CustomKeyboardEvent);
@@ -447,12 +443,12 @@
test('_handleDiffAgainstLatest', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(10),
};
element._patchRange = {
- basePatchNum: 1 as PatchSetNum,
- patchNum: 3 as PatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
};
sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
element._handleDiffAgainstLatest(
@@ -467,12 +463,12 @@
test('_handleDiffBaseAgainstLeft', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(10),
};
element._patchRange = {
- patchNum: 3 as PatchSetNum,
- basePatchNum: 1 as PatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
};
sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
element._handleDiffBaseAgainstLeft(
@@ -486,12 +482,12 @@
test('_handleDiffRightAgainstLatest', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(10),
};
element._patchRange = {
- basePatchNum: 1 as PatchSetNum,
- patchNum: 3 as PatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
};
sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
element._handleDiffRightAgainstLatest(
@@ -505,12 +501,12 @@
test('_handleDiffBaseAgainstLatest', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(10),
};
element._patchRange = {
- basePatchNum: 1 as PatchSetNum,
- patchNum: 3 as PatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
};
sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
element._handleDiffBaseAgainstLatest(
@@ -693,14 +689,14 @@
test('A toggles overlay when logged in', done => {
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(1),
messages: createChangeMessages(1),
};
element._change.labels = {};
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// element has latest info
revisions: createRevisions(1),
messages: createChangeMessages(1),
@@ -730,7 +726,7 @@
element._loggedIn = true;
element._loading = false;
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
actions: {
abandon: {
@@ -757,7 +753,7 @@
element._loggedIn = true;
element._loading = false;
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
actions: {
abandon: {
@@ -841,10 +837,10 @@
element._changeNum = TEST_NUMERIC_CHANGE_ID;
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
rev1: createRevision(),
},
@@ -909,7 +905,9 @@
});
suite('reloading drafts', () => {
- let reloadStub: SinonStubbedMember<typeof element.$.commentAPI.reloadDrafts>;
+ let reloadStub: SinonStubbedMember<
+ typeof element.$.commentAPI.reloadDrafts
+ >;
const drafts: {[path: string]: UIDraft[]} = {
'testfile.txt': [
{
@@ -965,7 +963,7 @@
suite('_recomputeComments', () => {
setup(() => {
element._changeNum = TEST_NUMERIC_CHANGE_ID;
- element._change = createChange();
+ element._change = createChangeViewChange();
flush();
// Fake computeDraftCount as its required for ChangeComments,
// see gr-comment-api#reloadDrafts.
@@ -976,7 +974,7 @@
computeDraftCount: () => 0,
} as ChangeComments)
);
- element._change = createChange();
+ element._change = createChangeViewChange();
element._changeNum = element._change._number;
});
@@ -1084,10 +1082,10 @@
element._changeNum = TEST_NUMERIC_CHANGE_ID;
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
rev2: createRevision(2),
rev1: createRevision(1),
@@ -1119,7 +1117,7 @@
setup(done => {
element._changeNum = TEST_NUMERIC_CHANGE_ID;
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
rev2: createRevision(2),
rev1: createRevision(1),
@@ -1243,7 +1241,7 @@
test('_changeStatuses', () => {
element._loading = false;
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
rev2: createRevision(2),
rev1: createRevision(1),
@@ -1265,7 +1263,6 @@
element._mergeable = true;
const expectedStatuses = ['Merged', 'WIP'];
assert.deepEqual(element._changeStatuses, expectedStatuses);
- assert.equal(element._changeStatus, expectedStatuses.join(', '));
flush();
const statusChips = element.shadowRoot!.querySelectorAll(
'gr-change-status'
@@ -1314,10 +1311,10 @@
element._changeNum = TEST_NUMERIC_CHANGE_ID;
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
const change = {
- ...createChange(),
+ ...createChangeViewChange(),
owner: createAccountWithIdNameAndEmail(),
revisions: {
rev2: createRevision(2),
@@ -1376,7 +1373,7 @@
test('comment events properly update diff drafts', () => {
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 2 as PatchSetNum,
+ patchNum: 2 as RevisionPatchSetNum,
};
const draft: DraftInfo = {
__draft: true,
@@ -1417,14 +1414,14 @@
test('change num change', () => {
const change = {
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
} as ParsedChangeInfo;
stubRestApi('getChangeDetail').returns(Promise.resolve(change));
element._changeNum = undefined;
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 2 as PatchSetNum,
+ patchNum: 2 as RevisionPatchSetNum,
};
element._change = change;
element.viewState.changeNum = null;
@@ -1526,7 +1523,7 @@
const value: AppElementChangeViewParams = {
...createAppElementChangeViewParams(),
view: GerritView.CHANGE,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
element._paramsChanged(value);
assert.isTrue(reloadStub.calledOnce);
@@ -1534,8 +1531,8 @@
element._initialLoadComplete = true;
- value.basePatchNum = 1 as PatchSetNum;
- value.patchNum = 2 as PatchSetNum;
+ value.basePatchNum = 1 as BasePatchSetNum;
+ value.patchNum = 2 as RevisionPatchSetNum;
element._paramsChanged(value);
assert.isFalse(reloadStub.calledTwice);
assert.isTrue(reloadPatchDependentStub.calledOnce);
@@ -1561,14 +1558,14 @@
const value: AppElementChangeViewParams = {
...createAppElementChangeViewParams(),
view: GerritView.CHANGE,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
element._paramsChanged(value);
element._initialLoadComplete = true;
- value.basePatchNum = 1 as PatchSetNum;
- value.patchNum = 2 as PatchSetNum;
+ value.basePatchNum = 1 as BasePatchSetNum;
+ value.patchNum = 2 as RevisionPatchSetNum;
element._paramsChanged(value);
assert.isTrue(reloadPortedCommentsStub.calledOnce);
});
@@ -1600,29 +1597,9 @@
});
});
- test('_computeMergedCommitInfo', () => {
- const dummyRevs: {[revisionId: string]: RevisionInfo} = {
- 1: createRevision(1),
- 2: createRevision(2),
- };
- assert.deepEqual(
- element._computeMergedCommitInfo('0' as CommitId, dummyRevs),
- {}
- );
- assert.deepEqual(
- element._computeMergedCommitInfo('1' as CommitId, dummyRevs),
- dummyRevs[1].commit
- );
-
- // Regression test for issue 5337.
- const commit = element._computeMergedCommitInfo('2' as CommitId, dummyRevs);
- assert.notDeepEqual(commit, dummyRevs[2]);
- assert.deepEqual(commit, dummyRevs[2].commit);
- });
-
test('_computeCopyTextForTitle', () => {
const change: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
_number: 123 as NumericChangeId,
subject: 'test subject',
revisions: {
@@ -1653,6 +1630,7 @@
revisions: {
rev1: createRevision(1),
},
+ current_revision: undefined,
};
assert.equal(element._getLatestRevisionSHA(change), 'rev1');
});
@@ -1660,7 +1638,7 @@
test('show commit message edit button', () => {
const change = createChange();
const mergedChanged: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
status: ChangeStatus.MERGED,
};
assert.isTrue(element._computeHideEditCommitMessage(false, false, change));
@@ -1679,15 +1657,14 @@
});
test('_handleCommitMessageSave trims trailing whitespace', () => {
- element._change = createChange();
+ element._change = createChangeViewChange();
// Response code is 500, because we want to avoid window reloading
const putStub = stubRestApi('putChangeCommitMessage').returns(
Promise.resolve(new Response(null, {status: 500}))
);
- const mockEvent = (content: string) => {
- return new CustomEvent('', {detail: {content}});
- };
+ const mockEvent = (content: string) =>
+ new CustomEvent('', {detail: {content}});
element._handleCommitMessageSave(mockEvent('test \n test '));
assert.equal(putStub.lastCall.args[1], 'test\n test');
@@ -1702,7 +1679,7 @@
test('_computeChangeIdCommitMessageError', () => {
let commitMessage = 'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
let change: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
};
assert.equal(
@@ -1711,7 +1688,7 @@
);
change = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
};
assert.equal(
@@ -1732,7 +1709,7 @@
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
].join('\n');
let change: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
};
assert.equal(
@@ -1740,7 +1717,7 @@
null
);
change = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
};
assert.equal(
@@ -1755,7 +1732,7 @@
'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
].join(' and ');
let change: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484' as ChangeId,
};
assert.equal(
@@ -1763,7 +1740,7 @@
null
);
change = {
- ...createChange(),
+ ...createChangeViewChange(),
change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483' as ChangeId,
};
assert.equal(
@@ -1801,7 +1778,7 @@
sinon.stub(element, '_changeChanged');
stubRestApi('getChangeDetail').returns(
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
current_revision: 'foo' as CommitId,
revisions: {foo: createRevision()},
@@ -1818,7 +1795,7 @@
sinon.stub(element, '_changeChanged');
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
current_revision: 'foo' as CommitId,
revisions: {foo: createRevision()},
@@ -1836,7 +1813,7 @@
const changeRevision = createRevision();
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
labels: {},
current_revision: 'foo' as CommitId,
revisions: {foo: {...changeRevision}},
@@ -1848,7 +1825,7 @@
};
sinon.stub(element, '_getEdit').callsFake(() =>
Promise.resolve({
- base_patch_set_number: 1 as PatchSetNum,
+ base_patch_set_number: 1 as BasePatchSetNum,
commit: {...editCommit},
base_revision: 'abc',
ref: 'some/ref' as GitRef,
@@ -1870,7 +1847,7 @@
test('_getBasePatchNum', () => {
const _change: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
'98da160735fb81604b4c40e93c368f380539dd0e': createRevision(),
},
@@ -1886,7 +1863,7 @@
};
const _change2: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
'98da160735fb81604b4c40e93c368f380539dd0e': {
...createRevision(1),
@@ -1908,7 +1885,7 @@
};
assert.equal(element._getBasePatchNum(_change2, _patchRange), -1);
- _patchRange.patchNum = 1 as PatchSetNum;
+ _patchRange.patchNum = 1 as RevisionPatchSetNum;
assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
});
@@ -1991,17 +1968,16 @@
});
test('revert dialog opened with revert param', done => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
const awaitPluginsLoadedStub = sinon
.stub(getPluginLoader(), 'awaitPluginsLoaded')
.callsFake(() => Promise.resolve());
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 2 as PatchSetNum,
+ patchNum: 2 as RevisionPatchSetNum,
};
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
rev1: createRevision(1),
rev2: createRevision(2),
@@ -2026,14 +2002,14 @@
suite('scroll related tests', () => {
test('document scrolling calls function to set scroll height', done => {
const originalHeight = document.body.scrollHeight;
- const scrollStub = sinon.stub(element, '_handleScroll').callsFake(() => {
+ const scrollStub = sinon.stub(element, 'handleScroll').callsFake(() => {
assert.isTrue(scrollStub.called);
document.body.style.height = `${originalHeight}px`;
scrollStub.restore();
done();
});
document.body.style.height = '10000px';
- element._handleScroll();
+ element.handleScroll();
});
test('scrollTop is set correctly', () => {
@@ -2062,14 +2038,14 @@
setup(() => {
sinon.stub(element.$.replyDialog, '_draftChanged');
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(1),
messages: createChangeMessages(1),
};
element._change.labels = {};
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// element has latest info
revisions: {rev1: createRevision()},
messages: createChangeMessages(1),
@@ -2154,14 +2130,14 @@
suite('commit message expand/collapse', () => {
setup(() => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(1),
messages: createChangeMessages(1),
};
element._change.labels = {};
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// new patchset was uploaded
revisions: createRevisions(2),
current_revision: getCurrentRevision(2),
@@ -2203,7 +2179,9 @@
});
suite('related changes expand/collapse', () => {
- let updateHeightSpy: SinonSpyMember<typeof element._updateRelatedChangeMaxHeight>;
+ let updateHeightSpy: SinonSpyMember<
+ typeof element._updateRelatedChangeMaxHeight
+ >;
setup(() => {
updateHeightSpy = sinon.spy(element, '_updateRelatedChangeMaxHeight');
});
@@ -2216,9 +2194,9 @@
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
sinon.stub(element, '_getScrollHeight').callsFake(() => 60);
sinon.stub(element, '_getLineHeight').callsFake(() => 5);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: true} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: true} as MediaQueryList));
const relatedChanges = element.shadowRoot!.querySelector(
'#relatedChanges'
) as GrRelatedChangesList;
@@ -2235,9 +2213,9 @@
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
sinon.stub(element, '_getScrollHeight').callsFake(() => 40);
sinon.stub(element, '_getLineHeight').callsFake(() => 5);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: true} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: true} as MediaQueryList));
const relatedChanges = element.shadowRoot!.querySelector(
'#relatedChanges'
) as GrRelatedChangesList;
@@ -2248,9 +2226,9 @@
test('relatedChangesToggle functions', () => {
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: false} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: false} as MediaQueryList));
assert.isTrue(element._relatedChangesCollapsed);
const relatedChangesToggleButton = element.shadowRoot!.querySelector(
'#relatedChangesToggleButton'
@@ -2267,9 +2245,9 @@
test('_updateRelatedChangeMaxHeight without commit toggle', () => {
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
sinon.stub(element, '_getLineHeight').callsFake(() => 12);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: false} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: false} as MediaQueryList));
// 50 (existing height) - 30 (extra height) = 20 (adjusted height).
// 20 (max existing height) % 12 (line height) = 6 (remainder).
@@ -2284,9 +2262,9 @@
element._latestCommitMessage = _.times(31, String).join('\n');
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
sinon.stub(element, '_getLineHeight').callsFake(() => 12);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: false} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: false} as MediaQueryList));
// 50 (existing height) % 12 (line height) = 2 (remainder).
// 50 (existing height) - 2 (remainder) = 48 (max height to set).
@@ -2303,9 +2281,9 @@
element._latestCommitMessage = _.times(31, String).join('\n');
sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
sinon.stub(element, '_getLineHeight').callsFake(() => 12);
- sinon.stub(window, 'matchMedia').callsFake(() => {
- return {matches: true} as MediaQueryList;
- });
+ sinon
+ .stub(window, 'matchMedia')
+ .callsFake(() => ({matches: true} as MediaQueryList));
element._updateRelatedChangeMaxHeight();
@@ -2334,20 +2312,15 @@
});
suite('update checks', () => {
- let startUpdateCheckTimerSpy: SinonSpyMember<typeof element._startUpdateCheckTimer>;
- let asyncStub: SinonStubbedMember<typeof element.async>;
+ let clock: SinonFakeTimers;
+ let startUpdateCheckTimerSpy: SinonSpyMember<
+ typeof element._startUpdateCheckTimer
+ >;
setup(() => {
+ clock = sinon.useFakeTimers();
startUpdateCheckTimerSpy = sinon.spy(element, '_startUpdateCheckTimer');
- asyncStub = sinon.stub(element, 'async').callsFake(f => {
- // Only fire the async callback one time.
- if (asyncStub.callCount > 1) {
- return 1;
- }
- f.call(element);
- return 1;
- });
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: createRevisions(1),
messages: createChangeMessages(1),
};
@@ -2356,7 +2329,7 @@
test('_startUpdateCheckTimer negative delay', () => {
const getChangeDetailStub = stubRestApi('getChangeDetail').returns(
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// element has latest info
revisions: {rev1: createRevision()},
messages: createChangeMessages(1),
@@ -2377,7 +2350,7 @@
const getChangeDetailStub = stubRestApi('getChangeDetail').callsFake(
() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// element has latest info
revisions: {rev1: createRevision()},
messages: createChangeMessages(1),
@@ -2389,14 +2362,14 @@
...createServerInfo(),
change: {...createChangeConfig(), update_delay: 12345},
};
+ clock.tick(12345 * 1000);
await flush();
assert.equal(startUpdateCheckTimerSpy.callCount, 2);
assert.isTrue(getChangeDetailStub.called);
- assert.equal(asyncStub.lastCall.args[1], 12345 * 1000);
});
- test('_startUpdateCheckTimer out-of-date shows an alert', done => {
+ test('_startUpdateCheckTimer out-of-date shows an alert', async () => {
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
...createChange(),
@@ -2407,22 +2380,25 @@
})
);
+ let alertMessage = 'alert not fired';
element.addEventListener('show-alert', e => {
- assert.equal(e.detail.message, 'A newer patch set has been uploaded');
- done();
+ alertMessage = e.detail.message;
});
element._serverConfig = {
...createServerInfo(),
change: {...createChangeConfig(), update_delay: 12345},
};
+ clock.tick(12345 * 1000);
+ await flush();
+ assert.equal(alertMessage, 'A newer patch set has been uploaded');
assert.equal(startUpdateCheckTimerSpy.callCount, 1);
});
test('_startUpdateCheckTimer respects _loading', async () => {
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// new patchset was uploaded
revisions: createRevisions(2),
current_revision: getCurrentRevision(2),
@@ -2435,16 +2411,17 @@
...createServerInfo(),
change: {...createChangeConfig(), update_delay: 12345},
};
+ clock.tick(12345 * 1000 * 2);
await flush();
// No toast, instead a second call to _startUpdateCheckTimer().
assert.equal(startUpdateCheckTimerSpy.callCount, 2);
});
- test('_startUpdateCheckTimer new status shows an alert', done => {
+ test('_startUpdateCheckTimer new status shows an alert', async () => {
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
// element has latest info
revisions: {rev1: createRevision()},
messages: createChangeMessages(1),
@@ -2453,44 +2430,50 @@
})
);
+ let alertMessage = 'alert not fired';
element.addEventListener('show-alert', e => {
- assert.equal(e.detail.message, 'This change has been merged');
- done();
+ alertMessage = e.detail.message;
});
element._serverConfig = {
...createServerInfo(),
change: {...createChangeConfig(), update_delay: 12345},
};
+ clock.tick(12345 * 1000);
+ await flush();
+
+ assert.equal(alertMessage, 'This change has been merged');
});
- test('_startUpdateCheckTimer new messages shows an alert', done => {
+ test('_startUpdateCheckTimer new messages shows an alert', async () => {
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {rev1: createRevision()},
// element has new message
messages: createChangeMessages(2),
current_revision: 'rev1' as CommitId,
})
);
+
+ let alertMessage = 'alert not fired';
element.addEventListener('show-alert', e => {
- assert.equal(
- e.detail.message,
- 'There are new messages on this change'
- );
- done();
+ alertMessage = e.detail.message;
});
element._serverConfig = {
...createServerInfo(),
change: {...createChangeConfig(), update_delay: 12345},
};
+ clock.tick(12345 * 1000);
+ await flush();
+
+ assert.equal(alertMessage, 'There are new messages on this change');
});
});
test('canStartReview computation', () => {
const change1: ChangeInfo = createChange();
const change2: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
actions: {
ready: {
enabled: true,
@@ -2498,7 +2481,7 @@
},
};
const change3: ChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
actions: {
ready: {
label: 'Ready for Review',
@@ -2552,25 +2535,19 @@
);
assert.isTrue(
callCompute(
- {basePatchNum: ParentPatchSetNum, patchNum: 1 as PatchSetNum},
+ {basePatchNum: ParentPatchSetNum, patchNum: 1 as RevisionPatchSetNum},
{...createAppElementChangeViewParams(), edit: true}
)
);
assert.isFalse(
callCompute(
- {basePatchNum: ParentPatchSetNum, patchNum: 1 as PatchSetNum},
- createAppElementChangeViewParams()
- )
- );
- assert.isFalse(
- callCompute(
- {basePatchNum: EditPatchSetNum, patchNum: 1 as PatchSetNum},
+ {basePatchNum: ParentPatchSetNum, patchNum: 1 as RevisionPatchSetNum},
createAppElementChangeViewParams()
)
);
assert.isTrue(
callCompute(
- {basePatchNum: 1 as PatchSetNum, patchNum: EditPatchSetNum},
+ {basePatchNum: 1 as BasePatchSetNum, patchNum: EditPatchSetNum},
createAppElementChangeViewParams()
)
);
@@ -2579,7 +2556,7 @@
test('_processEdit', () => {
element._patchRange = {};
const change: ParsedChangeInfo = {
- ...createChange(),
+ ...createChangeViewChange(),
current_revision: 'foo' as CommitId,
revisions: {
foo: {...createRevision(), actions: {cherrypick: {enabled: true}}},
@@ -2600,7 +2577,7 @@
const edit: EditInfo = {
ref: 'ref/test/abc' as GitRef,
base_revision: 'abc',
- base_patch_set_number: 1 as PatchSetNum,
+ base_patch_set_number: 1 as BasePatchSetNum,
commit: {...editCommit},
fetch: {},
};
@@ -2621,20 +2598,20 @@
);
// If _patchRange.patchNum is defined, do not load edit.
- element._patchRange.patchNum = 5 as PatchSetNum;
+ element._patchRange.patchNum = 5 as RevisionPatchSetNum;
change.current_revision = 'baz' as CommitId;
element._processEdit((mockChange = _.cloneDeep(change)), edit);
- assert.equal(element._patchRange.patchNum, 5 as PatchSetNum);
+ assert.equal(element._patchRange.patchNum, 5 as RevisionPatchSetNum);
assert.notOk(mockChange.revisions.bar.actions);
});
test('file-action-tap handling', () => {
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
};
const fileList = element.$.fileList;
const Actions = GrEditConstants.Actions;
@@ -2712,7 +2689,7 @@
const revision2: RevisionInfo = createRevision(2);
stubRestApi('getChangeDetail').returns(
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
aaa: revision1,
bbb: revision2,
@@ -2726,7 +2703,7 @@
sinon
.stub(element, '_getPreferences')
.returns(Promise.resolve(createPreferences()));
- element._patchRange = {patchNum: 2 as PatchSetNum};
+ element._patchRange = {patchNum: 2 as RevisionPatchSetNum};
return element._getChangeDetail().then(() => {
assert.strictEqual(element._selectedRevision, revision2);
@@ -2741,7 +2718,7 @@
const revision3 = createEditRevision();
stubRestApi('getChangeDetail').returns(
Promise.resolve({
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {
aaa: revision1,
bbb: revision2,
@@ -2763,9 +2740,9 @@
});
test('_sendShowChangeEvent', () => {
- const change = {...createChange(), labels: {}};
+ const change = {...createChangeViewChange(), labels: {}};
element._change = {...change};
- element._patchRange = {patchNum: 4 as PatchSetNum};
+ element._patchRange = {patchNum: 4 as RevisionPatchSetNum};
element._mergeable = true;
const showStub = sinon.stub(appContext.jsApiService, 'handleEvent');
element._sendShowChangeEvent();
@@ -2788,7 +2765,7 @@
navigateToChangeStub.restore();
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
revisions: {rev1: createRevision()},
};
});
@@ -2817,7 +2794,7 @@
});
element.set('_change.revisions.rev2', {_number: 2});
- element._patchRange = {patchNum: 1 as PatchSetNum};
+ element._patchRange = {patchNum: 1 as RevisionPatchSetNum};
flush();
fireEdit();
@@ -2833,7 +2810,7 @@
});
element.set('_change.revisions.rev2', {_number: 2});
- element._patchRange = {patchNum: 2 as PatchSetNum};
+ element._patchRange = {patchNum: 2 as RevisionPatchSetNum};
flush();
fireEdit();
@@ -2842,7 +2819,7 @@
test('_handleStopEditTap', done => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
};
sinon.stub(element.$.metadata, '_computeLabelNames');
navigateToChangeStub.restore();
@@ -2852,7 +2829,7 @@
done();
});
- element._patchRange = {patchNum: 1 as PatchSetNum};
+ element._patchRange = {patchNum: 1 as RevisionPatchSetNum};
element.$.actions.dispatchEvent(
new CustomEvent('stop-edit-tap', {bubbles: false})
);
@@ -2860,7 +2837,7 @@
suite('plugin endpoints', () => {
test('endpoint params', done => {
- element._change = {...createChange(), labels: {}};
+ element._change = {...createChangeViewChange(), labels: {}};
element._selectedRevision = createRevision();
let hookEl: HTMLElement;
let plugin: PluginApi;
@@ -2873,7 +2850,7 @@
.then(el => (hookEl = el));
},
'0.1',
- 'http://some/plugins/url.html'
+ 'http://some/plugins/url.js'
);
flush(() => {
assert.strictEqual((hookEl as any).plugin, plugin);
@@ -2887,7 +2864,7 @@
suite('_getMergeability', () => {
let getMergeableStub: SinonStubbedMember<RestApiService['getMergeable']>;
setup(() => {
- element._change = {...createChange(), labels: {}};
+ element._change = {...createChangeViewChange(), labels: {}};
getMergeableStub = stubRestApi('getMergeable').returns(
Promise.resolve({...createMergeable(), mergeable: true})
);
@@ -2939,7 +2916,7 @@
test('_handleToggleStar called when star is tapped', () => {
element._change = {
- ...createChange(),
+ ...createChangeViewChange(),
owner: {_account_id: 1 as AccountId},
starred: false,
};
@@ -2955,7 +2932,7 @@
setup(() => {
element._patchRange = {
basePatchNum: ParentPatchSetNum,
- patchNum: 1 as PatchSetNum,
+ patchNum: 1 as RevisionPatchSetNum,
};
sinon.stub(element, '_getChangeDetail').returns(Promise.resolve(false));
sinon.stub(element, '_getProjectConfig').returns(Promise.resolve());
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
index 18bd3a0..cc2f650 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-commit-info_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -31,9 +29,7 @@
}
@customElement('gr-commit-info')
-export class GrCommitInfo extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCommitInfo extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -85,6 +81,18 @@
});
}
+ computeCommitLink(
+ webLink?: string,
+ change?: ChangeInfo,
+ commitInfo?: CommitInfo,
+ serverConfig?: ServerInfo
+ ) {
+ if (webLink) return webLink;
+ const hash = this._computeShortHash(change, commitInfo, serverConfig);
+ if (hash === undefined) return '';
+ return GerritNav.getUrlForSearchQuery(hash);
+ }
+
_computeShortHash(
change?: ChangeInfo,
commitInfo?: CommitInfo,
@@ -94,7 +102,7 @@
return '';
}
- const {name} = this._getWeblink(change, commitInfo, serverConfig) || {};
- return name;
+ const weblink = this._getWeblink(change, commitInfo, serverConfig);
+ return weblink?.name ?? '';
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
index df0bb4a..65ca8b5 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
@@ -24,14 +24,12 @@
}
</style>
<div class="container">
- <template is="dom-if" if="[[_showWebLink]]">
- <a target="_blank" rel="noopener" href$="[[_webLink]]"
- >[[_computeShortHash(change, commitInfo, serverConfig)]]</a
- >
- </template>
- <template is="dom-if" if="[[!_showWebLink]]">
- [[_computeShortHash(change, commitInfo, serverConfig)]]
- </template>
+ <a
+ target="_blank"
+ rel="noopener"
+ href$="[[computeCommitLink(_webLink, change, commitInfo, serverConfig)]]"
+ >[[_computeShortHash(change, commitInfo, serverConfig)]]</a
+ >
<gr-copy-clipboard
has-tooltip=""
button-title="Copy full SHA to clipboard"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
index 10563ee..0954b7f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
@@ -17,8 +17,6 @@
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-abandon-dialog_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -37,12 +35,9 @@
}
}
-/**
- * @extends PolymerElement
- */
@customElement('gr-confirm-abandon-dialog')
export class GrConfirmAbandonDialog extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
+ PolymerElement
) {
static get template() {
return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
index 2f33858..75b6053 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-cherrypick-conflict-dialog_html';
import {customElement} from '@polymer/decorators';
@@ -29,9 +27,7 @@
}
@customElement('gr-confirm-cherrypick-conflict-dialog')
-export class GrConfirmCherrypickConflictDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmCherrypickConflictDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index ebcabbf..af565cb 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-cherrypick-dialog_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -75,9 +73,7 @@
}
@customElement('gr-confirm-cherrypick-dialog')
-export class GrConfirmCherrypickDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmCherrypickDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
index 6c0099e..d42f7e5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
@@ -120,9 +120,7 @@
</div></template
>
- <label for="branchInput">
- Cherry Pick to branch
- </label>
+ <label for="branchInput"> Cherry Pick to branch </label>
<gr-autocomplete
id="branchInput"
text="{{branch}}"
@@ -153,9 +151,7 @@
bind-value="{{baseCommit}}"
/>
</iron-input>
- <label for="messageInput">
- Cherry Pick Commit Message
- </label>
+ <label for="messageInput"> Cherry Pick Commit Message </label>
</template>
<template
is="dom-if"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
index 5e95e66..eb4053a 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -17,8 +17,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-dialog/gr-dialog';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-move-dialog_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -30,9 +28,7 @@
const SUGGESTIONS_LIMIT = 15;
@customElement('gr-confirm-move-dialog')
-export class GrConfirmMoveDialog extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrConfirmMoveDialog extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -59,7 +55,7 @@
project?: RepoName;
@property({type: Object})
- _query?: (_text?: string) => Promise<AutocompleteSuggestion[]>;
+ _query: (input: string) => Promise<AutocompleteSuggestion[]>;
get keyBindings() {
return {
@@ -71,7 +67,7 @@
constructor() {
super();
- this._query = () => this._getProjectBranchesSuggestions();
+ this._query = (text: string) => this._getProjectBranchesSuggestions(text);
}
_handleConfirmTap(e: Event) {
@@ -97,10 +93,9 @@
}
_getProjectBranchesSuggestions(
- input?: string
+ input: string
): Promise<AutocompleteSuggestion[]> {
if (!this.project) return Promise.reject(new Error('Missing project'));
- if (!input) return Promise.reject(new Error('Missing input'));
if (input.startsWith('refs/heads/')) {
input = input.substring('refs/heads/'.length);
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
index de75a39..7c3c719 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
@@ -56,9 +56,7 @@
<p class="warning">
Warning: moving a change will not change its parents.
</p>
- <label for="branchInput">
- Move change to branch
- </label>
+ <label for="branchInput"> Move change to branch </label>
<gr-autocomplete
id="branchInput"
text="{{branch}}"
@@ -66,9 +64,7 @@
placeholder="Destination branch"
>
</gr-autocomplete>
- <label for="messageInput">
- Move Change Message
- </label>
+ <label for="messageInput"> Move Change Message </label>
<iron-autogrow-textarea
id="messageInput"
class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js
index db00f6b..36a2ad3 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js
@@ -64,5 +64,12 @@
done();
});
});
+
+ test('_getProjectBranchesSuggestions input empty string', done => {
+ element._getProjectBranchesSuggestions('').then(branches => {
+ assert.equal(branches.length, 0);
+ done();
+ });
+ });
});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
index b2b6e61..4e6c963 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
@@ -17,8 +17,6 @@
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-rebase-dialog_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -49,9 +47,7 @@
}
@customElement('gr-confirm-rebase-dialog')
-export class GrConfirmRebaseDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmRebaseDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
index 7d28de6..6def4a5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
@@ -108,9 +108,7 @@
/>
<label id="rebaseOnOtherLabel" for="rebaseOnOtherInput">
Rebase on a specific change, ref, or commit
- <span hidden$="[[!hasParent]]">
- (breaks relation chain)
- </span>
+ <span hidden$="[[!hasParent]]"> (breaks relation chain) </span>
</label>
</div>
<div class="parentRevisionContainer">
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
index e10b12b..450551b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
@@ -17,8 +17,6 @@
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-revert-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -41,9 +39,7 @@
}
@customElement('gr-confirm-revert-dialog')
-export class GrConfirmRevertDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmRevertDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
index a4e3e96..17647ad 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
@@ -53,9 +53,7 @@
on-confirm="_handleConfirmTap"
on-cancel="_handleCancelTap"
>
- <div class="header" slot="header">
- Revert Merged Change
- </div>
+ <div class="header" slot="header">Revert Merged Change</div>
<div class="main" slot="main">
<div class="error" hidden$="[[!_showErrorMessage]]">
<span> A reason is required </span>
@@ -87,9 +85,7 @@
</div></template
>
<gr-endpoint-decorator name="confirm-revert-change">
- <label for="messageInput">
- Revert Commit Message
- </label>
+ <label for="messageInput"> Revert Commit Message </label>
<iron-autogrow-textarea
id="messageInput"
class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
index 9e1256f..bd268fd 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-revert-submission-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -29,9 +27,7 @@
const CHANGE_SUBJECT_LIMIT = 50;
@customElement('gr-confirm-revert-submission-dialog')
-export class GrConfirmRevertSubmissionDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmRevertSubmissionDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
index 49a9c70..48bd796 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
@@ -45,9 +45,7 @@
>
<div class="header" slot="header">Revert Submission</div>
<div class="main" slot="main">
- <label for="messageInput">
- Revert Commit Message
- </label>
+ <label for="messageInput"> Revert Commit Message </label>
<iron-autogrow-textarea
id="messageInput"
class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
index df0678ee..33f7304 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
@@ -21,8 +21,6 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../../styles/shared-styles';
import '../gr-thread-list/gr-thread-list';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-submit-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -37,9 +35,7 @@
};
}
@customElement('gr-confirm-submit-dialog')
-export class GrConfirmSubmitDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmSubmitDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
index 29b3752..e4662da 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
@@ -44,9 +44,7 @@
on-confirm="_handleConfirmTap"
>
<template is="dom-if" if="[[_initialised]]">
- <div class="header" slot="header">
- [[action.label]]
- </div>
+ <div class="header" slot="header">[[action.label]]</div>
<div class="main" slot="main">
<gr-endpoint-decorator name="confirm-submit-change">
<p>Ready to submit “<strong>[[change.subject]]</strong>”?</p>
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.js
deleted file mode 100644
index e175fda..0000000
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-confirm-submit-dialog.js';
-
-const basicFixture = fixtureFromElement('gr-confirm-submit-dialog');
-
-suite('gr-file-list-header tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- element._initialised = true;
- });
-
- test('display', () => {
- element.action = {label: 'my-label'};
- element.change = {
- subject: 'my-subject',
- revisions: {},
- };
- flush();
- const header = element.shadowRoot
- .querySelector('.header');
- assert.equal(header.textContent.trim(), 'my-label');
-
- const message = element.shadowRoot
- .querySelector('.main p');
- assert.notEqual(message.textContent.length, 0);
- assert.notEqual(message.textContent.indexOf('my-subject'), -1);
- });
-
- test('_computeUnresolvedCommentsWarning', () => {
- const change = {unresolved_comment_count: 1};
- assert.equal(element._computeUnresolvedCommentsWarning(change),
- 'Heads Up! 1 unresolved comment.');
-
- const change2 = {unresolved_comment_count: 2};
- assert.equal(element._computeUnresolvedCommentsWarning(change2),
- 'Heads Up! 2 unresolved comments.');
- });
-
- test('_computeHasChangeEdit', () => {
- const change = {
- revisions: {
- d442ff05d6c4f2a3af0eeca1f67374b39f9dc3d8: {
- _number: 'edit',
- },
- },
- unresolved_comment_count: 0,
- };
-
- assert.equal(element._computeHasChangeEdit(change), true);
-
- const change2 = {
- revisions: {
- d442ff05d6c4f2a3af0eeca1f67374b39f9dc3d8: {
- _number: 2,
- },
- },
- };
- assert.equal(element._computeHasChangeEdit(change2), false);
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.ts
new file mode 100644
index 0000000..e9f3019
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_test.ts
@@ -0,0 +1,89 @@
+/**
+ * @license
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import {createChange, createRevision} from '../../../test/test-data-generators';
+import {queryAndAssert} from '../../../test/test-utils';
+import {PatchSetNum} from '../../../types/common';
+import {GrConfirmSubmitDialog} from './gr-confirm-submit-dialog';
+
+const basicFixture = fixtureFromElement('gr-confirm-submit-dialog');
+
+suite('gr-confirm-submit-dialog tests', () => {
+ let element: GrConfirmSubmitDialog;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ element._initialised = true;
+ });
+
+ test('display', () => {
+ element.action = {label: 'my-label'};
+ element.change = {
+ ...createChange(),
+ subject: 'my-subject',
+ revisions: {},
+ };
+ flush();
+ const header = queryAndAssert(element, '.header');
+ assert.equal(header.textContent!.trim(), 'my-label');
+
+ const message = queryAndAssert(element, '.main p');
+ assert.isNotEmpty(message.textContent);
+ assert.notEqual(message.textContent!.indexOf('my-subject'), -1);
+ });
+
+ test('_computeUnresolvedCommentsWarning', () => {
+ const change = {...createChange(), unresolved_comment_count: 1};
+ assert.equal(
+ element._computeUnresolvedCommentsWarning(change),
+ 'Heads Up! 1 unresolved comment.'
+ );
+
+ const change2 = {...createChange(), unresolved_comment_count: 2};
+ assert.equal(
+ element._computeUnresolvedCommentsWarning(change2),
+ 'Heads Up! 2 unresolved comments.'
+ );
+ });
+
+ test('_computeHasChangeEdit', () => {
+ const change = {
+ ...createChange(),
+ revisions: {
+ d442ff05d6c4f2a3af0eeca1f67374b39f9dc3d8: {
+ ...createRevision(),
+ _number: 'edit' as PatchSetNum,
+ },
+ },
+ unresolved_comment_count: 0,
+ };
+
+ assert.isTrue(element._computeHasChangeEdit(change));
+
+ const change2 = {
+ ...createChange(),
+ revisions: {
+ d442ff05d6c4f2a3af0eeca1f67374b39f9dc3d8: {
+ ...createRevision(),
+ _number: 2 as PatchSetNum,
+ },
+ },
+ };
+ assert.isFalse(element._computeHasChangeEdit(change2));
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index ab1e4e6..fe1b618 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../../shared/gr-download-commands/gr-download-commands';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-download-dialog_html';
import {changeBaseURL, getRevisionKey} from '../../../utils/change-util';
@@ -38,9 +36,7 @@
}
@customElement('gr-download-dialog')
-export class GrDownloadDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDownloadDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index 146b3e2..e94f67e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -18,26 +18,17 @@
import '../../diff/gr-diff-mode-selector/gr-diff-mode-selector';
import '../../diff/gr-patch-range-select/gr-patch-range-select';
import '../../edit/gr-edit-controls/gr-edit-controls';
-import '../../shared/gr-editable-label/gr-editable-label';
-import '../../shared/gr-linked-chip/gr-linked-chip';
import '../../shared/gr-select/gr-select';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-icons/gr-icons';
import '../gr-commit-info/gr-commit-info';
-import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-file-list-header_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {FilesExpandedState} from '../gr-file-list-constants';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import {
- computeLatestPatchNum,
- getRevisionByPatchNum,
- PatchSet,
-} from '../../../utils/patch-set-util';
-import {property, computed, observe, customElement} from '@polymer/decorators';
+import {computeLatestPatchNum, PatchSet} from '../../../utils/patch-set-util';
+import {property, customElement} from '@polymer/decorators';
import {
AccountInfo,
ChangeInfo,
@@ -46,17 +37,15 @@
ServerInfo,
RevisionInfo,
NumericChangeId,
+ BasePatchSetNum,
} from '../../../types/common';
import {DiffPreferencesInfo} from '../../../types/diff';
import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
import {GrDiffModeSelector} from '../../diff/gr-diff-mode-selector/gr-diff-mode-selector';
-import {DiffViewMode} from '../../../constants/constants';
+import {ChangeStatus, DiffViewMode} from '../../../constants/constants';
import {GrButton} from '../../shared/gr-button/gr-button';
-import {appContext} from '../../../services/app-context';
import {fireEvent} from '../../../utils/event-util';
-// Maximum length for patch set descriptions.
-const PATCH_DESC_MAX_LENGTH = 500;
const MERGED_STATUS = 'MERGED';
declare global {
@@ -74,9 +63,7 @@
}
@customElement('gr-file-list-header')
-export class GrFileListHeader extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrFileListHeader extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -101,10 +88,6 @@
* @event open-download-dialog
*/
- /**
- * @event open-upload-help-dialog
- */
-
@property({type: Object})
account: AccountInfo | undefined;
@@ -151,7 +134,7 @@
patchNum?: PatchSetNum;
@property({type: String})
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
@property({type: String})
filesExpanded?: FilesExpandedState;
@@ -161,30 +144,9 @@
@property({type: Number})
readonly _maxFilesForBulkActions = 225;
- @property({type: String})
- _patchsetDescription = '';
-
@property({type: Object})
revisionInfo?: RevisionInfo;
- private readonly restApiService = appContext.restApiService;
-
- @computed('loggedIn', 'change', 'account')
- get _descriptionReadOnly(): boolean {
- if (
- this.loggedIn === undefined ||
- this.change === undefined ||
- this.account === undefined
- ) {
- return true;
- }
-
- return !(
- this.loggedIn &&
- this.account._account_id === this.change.owner._account_id
- );
- }
-
setDiffViewMode(mode: DiffViewMode) {
this.$.modeSelect.setMode(mode);
}
@@ -200,109 +162,15 @@
_computeExpandedClass(filesExpanded: FilesExpandedState) {
const classes = [];
if (filesExpanded === FilesExpandedState.ALL) {
- classes.push('expanded');
- }
- if (
- filesExpanded === FilesExpandedState.SOME ||
- filesExpanded === FilesExpandedState.ALL
- ) {
classes.push('openFile');
+ classes.push('allExpanded');
+ } else if (filesExpanded === FilesExpandedState.SOME) {
+ classes.push('openFile');
+ classes.push('someExpanded');
}
return classes.join(' ');
}
- _computeDescriptionPlaceholder(readOnly: boolean) {
- return (readOnly ? 'No' : 'Add') + ' patchset description';
- }
-
- @observe('change', 'patchNum')
- _computePatchSetDescription(change: ChangeInfo, patchNum: PatchSetNum) {
- // Polymer 2: check for undefined
- if (
- change === undefined ||
- change.revisions === undefined ||
- patchNum === undefined
- ) {
- return;
- }
-
- const rev = getRevisionByPatchNum(
- Object.values(change.revisions),
- patchNum
- );
- this._patchsetDescription = rev?.description
- ? rev.description.substring(0, PATCH_DESC_MAX_LENGTH)
- : '';
- }
-
- _handleDescriptionRemoved(e: CustomEvent) {
- return this._updateDescription('', e);
- }
-
- /**
- * @param revisions The revisions object keyed by revision hashes
- * @param patchSet A revision already fetched from {revisions}
- * @return the SHA hash corresponding to the revision.
- */
- _getPatchsetHash(
- revisions: {[revisionId: string]: RevisionInfo},
- patchSet: RevisionInfo
- ) {
- for (const sha of Object.keys(revisions)) {
- if (revisions[sha] === patchSet) {
- return sha;
- }
- }
- throw new Error('patchset hash not found');
- }
-
- _handleDescriptionChanged(e: CustomEvent) {
- const desc = e.detail.trim();
- this._updateDescription(desc, e);
- }
-
- /**
- * Update the patchset description with the rest API.
- */
- _updateDescription(desc: string, e: CustomEvent) {
- if (
- !this.change ||
- !this.change.revisions ||
- !this.patchNum ||
- !this.changeNum
- )
- return;
- // target can be either gr-editable-label or gr-linked-chip
- const target = (dom(e) as EventApi).rootTarget as HTMLElement & {
- disabled: boolean;
- };
- if (target) {
- target.disabled = true;
- }
- const rev = getRevisionByPatchNum(
- Object.values(this.change.revisions),
- this.patchNum
- )!;
- const sha = this._getPatchsetHash(this.change.revisions, rev);
- return this.restApiService
- .setDescription(this.changeNum, this.patchNum, desc)
- .then((res: Response) => {
- if (res.ok) {
- if (target) {
- target.disabled = false;
- }
- this.set(['change', 'revisions', sha, 'description'], desc);
- this._patchsetDescription = desc;
- }
- })
- .catch(() => {
- if (target) {
- target.disabled = false;
- }
- return;
- });
- }
-
_computePrefsButtonHidden(
prefs: DiffPreferencesInfo,
diffPrefsDisabled: boolean
@@ -317,6 +185,13 @@
return shownFileCount <= maxFilesForBulkActions;
}
+ _showAddPatchsetDescription(
+ patchsetDescription: string,
+ change?: ChangeInfo
+ ) {
+ return !patchsetDescription && change?.status === ChangeStatus.NEW;
+ }
+
_handlePatchChange(e: CustomEvent) {
const {basePatchNum, patchNum} = e.detail;
if (
@@ -361,21 +236,4 @@
_hideIncludedIn(change?: ChangeInfo) {
return change?.status === MERGED_STATUS ? '' : 'hide';
}
-
- _handleUploadTap(e: Event) {
- e.preventDefault();
- e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('open-upload-help-dialog', {bubbles: false})
- );
- }
-
- _computeUploadHelpContainerClass(change: ChangeInfo, account: AccountInfo) {
- const changeIsMerged = change?.status === MERGED_STATUS;
- const ownerId = change?.owner?._account_id || null;
- const userId = account && account._account_id;
- const userIsOwner = ownerId && userId && ownerId === userId;
- const hideContainer = !userIsOwner || changeIsMerged;
- return 'uploadContainer desktop' + (hideContainer ? ' hide' : '');
- }
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
index af72b67..8ebb029 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
@@ -53,9 +53,6 @@
.latestPatchContainer a {
text-decoration: none;
}
- gr-editable-label.descriptionLabel {
- max-width: 100%;
- }
.mobile {
display: none;
}
@@ -82,17 +79,15 @@
justify-content: flex-end;
}
#collapseBtn,
- .expanded #expandBtn,
+ .allExpanded #expandBtn,
.fileViewActions {
display: none;
}
- .expanded #expandBtn {
- display: none;
+ .someExpanded #expandBtn {
+ margin-right: 8px;
}
- gr-linked-chip {
- --linked-chip-text-color: var(--primary-text-color);
- }
- .expanded #collapseBtn,
+ .someExpanded #collapseBtn,
+ .allExpanded #collapseBtn,
.openFile .fileViewActions {
align-items: center;
display: flex;
@@ -164,29 +159,6 @@
<span class="separator"></span>
<a href$="[[changeUrl]]">Go to latest patch set</a>
</span>
- <span class="container descriptionContainer hideOnEdit">
- <span class="separator"></span>
- <template is="dom-if" if="[[_patchsetDescription]]">
- <gr-linked-chip
- id="descriptionChip"
- text="[[_patchsetDescription]]"
- removable="[[!_descriptionReadOnly]]"
- on-remove="_handleDescriptionRemoved"
- ></gr-linked-chip>
- </template>
- <template is="dom-if" if="[[!_patchsetDescription]]">
- <gr-editable-label
- id="descriptionLabel"
- uppercase=""
- class="descriptionLabel"
- label-text="Add patchset description"
- value="[[_patchsetDescription]]"
- placeholder="[[_computeDescriptionPlaceholder(_descriptionReadOnly)]]"
- read-only="[[_descriptionReadOnly]]"
- on-changed="_handleDescriptionChanged"
- ></gr-editable-label>
- </template>
- </span>
</div>
</div>
<div class$="rightControls [[_computeExpandedClass(filesExpanded)]]">
@@ -200,11 +172,6 @@
<span class="separator"></span>
</span>
</template>
- <span class$="[[_computeUploadHelpContainerClass(change, account)]]">
- <gr-button link="" class="upload" on-click="_handleUploadTap"
- >Update Change</gr-button
- >
- </span>
<span class="downloadContainer desktop">
<gr-button
link=""
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
index f877527..dd70678 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
@@ -59,99 +59,6 @@
assert.isFalse(element.$.diffPrefsContainer.hidden);
});
- test('_computeDescriptionReadOnly', () => {
- element.loggedIn = false;
- element.change = {owner: {_account_id: 1}};
- element.account = {_account_id: 1};
- assert.equal(element._descriptionReadOnly, true);
-
- element.loggedIn = true;
- element.change = {owner: {_account_id: 0}};
- element.account = {_account_id: 1};
- assert.equal(element._descriptionReadOnly, true);
-
- element.loggedIn = true;
- element.change = {owner: {_account_id: 1}};
- element.account = {_account_id: 1};
- assert.equal(element._descriptionReadOnly, false);
- });
-
- test('_computeDescriptionPlaceholder', () => {
- assert.equal(element._computeDescriptionPlaceholder(true),
- 'No patchset description');
- assert.equal(element._computeDescriptionPlaceholder(false),
- 'Add patchset description');
- });
-
- test('description editing', () => {
- const putDescStub = stubRestApi('setDescription')
- .returns(Promise.resolve({ok: true}));
-
- element.changeNum = '42';
- element.basePatchNum = 'PARENT';
- element.patchNum = 1;
-
- element.change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- revisions: {
- rev1: {_number: 1, description: 'test', commit: {commit: 'rev1'}},
- },
- current_revision: 'rev1',
- status: 'NEW',
- labels: {},
- actions: {},
- owner: {_account_id: 1},
- };
- element.account = {_account_id: 1};
- element.owner = {_account_id: 1};
- element.loggedIn = true;
-
- flush();
-
- // The element has a description, so the account chip should be visible
- element.owner = {_account_id: 1};
- // and the description label should not exist.
- const chip = element.root.querySelector('#descriptionChip');
- let label = element.root.querySelector('#descriptionLabel');
-
- assert.equal(chip.text, 'test');
- assert.isNotOk(label);
-
- // Simulate tapping the remove button, but call function directly so that
- // can determine what happens after the promise is resolved.
- return element._handleDescriptionRemoved()
- .then(() => {
- // The API stub should be called with an empty string for the new
- // description.
- assert.equal(putDescStub.lastCall.args[2], '');
- assert.equal(element.change.revisions.rev1.description, '');
-
- flush();
- // The editable label should now be visible and the chip hidden.
- label = element.root.querySelector('#descriptionLabel');
- assert.isOk(label);
- assert.equal(getComputedStyle(chip).display, 'none');
- assert.notEqual(getComputedStyle(label).display, 'none');
- assert.isFalse(label.readOnly);
- // Edit the label to have a new value of test2, and save.
- label.editing = true;
- label._inputText = 'test2';
- label._save();
- flush();
- // The API stub should be called with an `test2` for the new
- // description.
- assert.equal(putDescStub.callCount, 2);
- assert.equal(putDescStub.lastCall.args[2], 'test2');
- })
- .then(() => {
- flush();
- // The chip should be visible again, and the label hidden.
- assert.equal(element.change.revisions.rev1.description, 'test2');
- assert.equal(getComputedStyle(label).display, 'none');
- assert.notEqual(getComputedStyle(chip).display, 'none');
- });
- });
-
test('expandAllDiffs called when expand button clicked', () => {
element.shownFileCount = 1;
flush();
@@ -161,7 +68,7 @@
assert.isTrue(element._expandAllDiffs.called);
});
- test('collapseAllDiffs called when expand button clicked', () => {
+ test('collapseAllDiffs called when collapse button clicked', () => {
element.shownFileCount = 1;
flush();
sinon.stub(element, '_collapseAllDiffs');
@@ -203,20 +110,29 @@
});
test('expand/collapse buttons are toggled correctly', () => {
+ // Only the expand button should be visible in the initial state when
+ // NO files are expanded.
element.shownFileCount = 10;
flush();
const expandBtn = element.shadowRoot.querySelector('#expandBtn');
const collapseBtn = element.shadowRoot.querySelector('#collapseBtn');
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
assert.equal(getComputedStyle(collapseBtn).display, 'none');
+
+ // Both expand and collapse buttons should be visible when SOME files are
+ // expanded.
element.filesExpanded = FilesExpandedState.SOME;
flush();
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
- assert.equal(getComputedStyle(collapseBtn).display, 'none');
+ assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
+
+ // Only the collapse button should be visible when ALL files are expanded.
element.filesExpanded = FilesExpandedState.ALL;
flush();
assert.equal(getComputedStyle(expandBtn).display, 'none');
assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
+
+ // Only the expand button should be visible when NO files are expanded.
element.filesExpanded = FilesExpandedState.NONE;
flush();
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
@@ -271,14 +187,10 @@
flush();
assert.isFalse(isVisible(element.$.diffPrefsContainer));
- assert.isFalse(isVisible(element.shadowRoot
- .querySelector('.descriptionContainer')));
element.editMode = false;
flush();
- assert.isTrue(isVisible(element.shadowRoot
- .querySelector('.descriptionContainer')));
assert.isTrue(isVisible(element.$.diffPrefsContainer));
});
@@ -300,17 +212,6 @@
assert.isFalse(isVisible(element.shadowRoot
.querySelector('#editControls').parentElement));
});
-
- test('_computeUploadHelpContainerClass', () => {
- // Only show the upload helper button when an unmerged change is viewed
- // by its owner.
- const accountA = {_account_id: 1};
- const accountB = {_account_id: 2};
- assert.notInclude(element._computeUploadHelpContainerClass(
- {owner: accountA}, accountA), 'hide');
- assert.include(element._computeUploadHelpContainerClass(
- {owner: accountA}, accountB), 'hide');
- });
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index c2947a6..4b5525a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -28,11 +28,9 @@
import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
import '../../shared/gr-file-status-chip/gr-file-status-chip';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-file-list_html';
-import {asyncForeach} from '../../../utils/async-util';
+import {asyncForeach, debounce, DelayedTask} from '../../../utils/async-util';
import {
KeyboardShortcutMixin,
Modifier,
@@ -44,8 +42,12 @@
import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {appContext} from '../../../services/app-context';
-import {DiffViewMode, SpecialFilePath} from '../../../constants/constants';
-import {descendedFromClass} from '../../../utils/dom-util';
+import {
+ DiffViewMode,
+ ScrollMode,
+ SpecialFilePath,
+} from '../../../constants/constants';
+import {descendedFromClass, toggleClass} from '../../../utils/dom-util';
import {
addUnmodifiedFiles,
computeDisplayPath,
@@ -73,6 +75,7 @@
import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
import {CustomKeyboardEvent} from '../../../types/events';
import {ParsedChangeInfo, PatchSetFile} from '../../../types/types';
+import {Timing} from '../../../constants/reporting';
export const DEFAULT_NUM_FILES_SHOWN = 200;
@@ -83,18 +86,12 @@
const SIZE_BAR_GAP_WIDTH = 1;
const SIZE_BAR_MIN_WIDTH = 1.5;
-const RENDER_TIMING_LABEL = 'FileListRenderTime';
-const RENDER_AVG_TIMING_LABEL = 'FileListRenderTimePerFile';
-const EXPAND_ALL_TIMING_LABEL = 'ExpandAllDiffs';
-const EXPAND_ALL_AVG_TIMING_LABEL = 'ExpandAllPerDiff';
-
const FILE_ROW_CLASS = 'file-row';
export interface GrFileList {
$: {
diffPreferencesDialog: GrDiffPreferencesDialog;
diffCursor: GrDiffCursor;
- fileCursor: GrCursorManager;
};
}
@@ -152,8 +149,6 @@
export type FileNameToReviewedFileInfoMap = {[name: string]: ReviewedFileInfo};
-const DEBOUNCER_LOADING_CHANGE = 'loading-change';
-
/**
* Type for FileInfo
*
@@ -170,9 +165,7 @@
*/
@customElement('gr-file-list')
-export class GrFileList extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrFileList extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -281,6 +274,8 @@
private _cancelForEachDiff?: () => void;
+ loadingTask?: DelayedTask;
+
@property({
type: Boolean,
computed:
@@ -349,15 +344,19 @@
};
}
- /** @override */
- created() {
- super.created();
+ private fileCursor = new GrCursorManager();
+
+ constructor() {
+ super();
+ this.fileCursor.scrollMode = ScrollMode.KEEP_VISIBLE;
+ this.fileCursor.cursorTargetClass = 'selected';
+ this.fileCursor.focusOnMove = true;
this.addEventListener('keydown', e => this._scopedKeydownHandler(e));
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
getPluginLoader()
.awaitPluginsLoaded()
.then(() => {
@@ -405,10 +404,11 @@
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
+ this.fileCursor.unsetCursor();
this._cancelDiffs();
- this.cancelDebouncer(DEBOUNCER_LOADING_CHANGE);
+ this.loadingTask?.cancel();
+ super.disconnectedCallback();
}
/**
@@ -554,7 +554,7 @@
return;
}
// Re-render all expanded diffs sequentially.
- this.reporting.time(EXPAND_ALL_TIMING_LABEL);
+ this.reporting.time(Timing.FILE_EXPAND_ALL);
this._renderInOrder(
this._expandedFiles,
this.diffs,
@@ -789,7 +789,7 @@
e.preventDefault();
// Prevent _handleFileListClick handler call
e.stopPropagation();
- this.$.fileCursor.setCursor(fileRow.element);
+ this.fileCursor.setCursor(fileRow.element);
fileAction(fileRow.file);
}
}
@@ -829,7 +829,7 @@
}
e.preventDefault();
- this.$.fileCursor.setCursor(fileRow.element);
+ this.fileCursor.setCursor(fileRow.element);
this._toggleFileExpanded(file);
}
@@ -886,13 +886,13 @@
if (
this.shouldSuppressKeyboardShortcut(e) ||
this.modifierPressed(e) ||
- this.$.fileCursor.index === -1
+ this.fileCursor.index === -1
) {
return;
}
e.preventDefault();
- this._toggleFileExpandedByIndex(this.$.fileCursor.index);
+ this._toggleFileExpandedByIndex(this.fileCursor.index);
}
_handleToggleAllInlineDiffs(e: CustomKeyboardEvent) {
@@ -910,7 +910,7 @@
}
e.preventDefault();
- this.toggleClass('hideComments');
+ toggleClass(this, 'hideComments');
}
_handleCursorNext(e: CustomKeyboardEvent) {
@@ -928,8 +928,8 @@
return;
}
e.preventDefault();
- this.$.fileCursor.next();
- this.selectedIndex = this.$.fileCursor.index;
+ this.fileCursor.next();
+ this.selectedIndex = this.fileCursor.index;
}
}
@@ -948,8 +948,8 @@
return;
}
e.preventDefault();
- this.$.fileCursor.previous();
- this.selectedIndex = this.$.fileCursor.index;
+ this.fileCursor.previous();
+ this.selectedIndex = this.fileCursor.index;
}
}
@@ -1044,10 +1044,10 @@
}
e.preventDefault();
- if (!this._files[this.$.fileCursor.index]) {
+ if (!this._files[this.fileCursor.index]) {
return;
}
- this._reviewFile(this._files[this.$.fileCursor.index].__path);
+ this._reviewFile(this._files[this.fileCursor.index].__path);
}
_handleToggleLeftPane(e: CustomKeyboardEvent) {
@@ -1084,9 +1084,9 @@
_openSelectedFile(index?: number) {
if (index !== undefined) {
- this.$.fileCursor.setCursorAtIndex(index);
+ this.fileCursor.setCursorAtIndex(index);
}
- if (!this._files[this.$.fileCursor.index]) {
+ if (!this._files[this.fileCursor.index]) {
return;
}
if (!this.change || !this.patchRange) {
@@ -1094,7 +1094,7 @@
}
GerritNav.navigateToDiff(
this.change,
- this._files[this.$.fileCursor.index].__path,
+ this._files[this.fileCursor.index].__path,
this.patchRange.patchNum,
this.patchRange.basePatchNum
);
@@ -1272,7 +1272,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(Timing.FILE_RENDER);
// How many more files are being shown (if it's an increase).
this._reportinShownFilesIncrement = Math.max(
@@ -1296,10 +1296,10 @@
_filesChanged() {
if (this._files && this._files.length > 0) {
flush();
- this.$.fileCursor.stops = Array.from(
+ this.fileCursor.stops = Array.from(
this.root!.querySelectorAll(`.${FILE_ROW_CLASS}`)
);
- this.$.fileCursor.setCursorAtIndex(this.selectedIndex, true);
+ this.fileCursor.setCursorAtIndex(this.selectedIndex, true);
}
}
@@ -1420,7 +1420,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(Timing.FILE_EXPAND_ALL);
if (newFiles.length) {
this._renderInOrder(newFiles, this.diffs, newFiles.length);
@@ -1499,8 +1499,8 @@
this._cancelForEachDiff = undefined;
console.info('Finished expanding', initialCount, 'diff(s)');
this.reporting.timeEndWithAverage(
- EXPAND_ALL_TIMING_LABEL,
- EXPAND_ALL_AVG_TIMING_LABEL,
+ Timing.FILE_EXPAND_ALL,
+ Timing.FILE_EXPAND_ALL_AVG,
initialCount
);
/* Block diff cursor from auto scrolling after files are done rendering.
@@ -1595,8 +1595,8 @@
* are reasonably fast.
*/
_loadingChanged(loading?: boolean) {
- this.debounce(
- DEBOUNCER_LOADING_CHANGE,
+ this.loadingTask = debounce(
+ this.loadingTask,
() => {
// Only show set the loading if there have been files loaded to show. In
// this way, the gray loading style is not shown on initial loads.
@@ -1778,10 +1778,10 @@
*/
_reportRenderedRow(index: number) {
if (index === this._shownFiles.length - 1) {
- this.async(() => {
+ setTimeout(() => {
this.reporting.timeEndWithAverage(
- RENDER_TIMING_LABEL,
- RENDER_AVG_TIMING_LABEL,
+ Timing.FILE_RENDER,
+ Timing.FILE_RENDER_AVG,
this._reportinShownFilesIncrement
);
}, 1);
@@ -1816,6 +1816,16 @@
_computeTruncatedPath(path: string) {
return computeTruncatedPath(path);
}
+
+ _getOldPath(file: NormalizedFileInfo) {
+ // The gr-endpoint-decorator is waiting until all gr-endpoint-param
+ // values are updated.
+ // The old_path property is undefined for added files, and the
+ // gr-endpoint-param value bound to file.old_path is never updates.
+ // As a results, the gr-endpoint-decorator doesn't work for added files.
+ // As a workaround, this method returns null instead of undefined.
+ return file.old_path ?? null;
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
index c57a2d5..89983ad 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
@@ -375,6 +375,8 @@
</gr-endpoint-param>
<gr-endpoint-param name="path" value="[[file.__path]]">
</gr-endpoint-param>
+ <gr-endpoint-param name="oldPath" value="[[_getOldPath(file)]]">
+ </gr-endpoint-param>
</gr-endpoint-decorator>
</template>
</template>
@@ -735,10 +737,4 @@
>
</gr-diff-preferences-dialog>
<gr-diff-cursor id="diffCursor"></gr-diff-cursor>
- <gr-cursor-manager
- id="fileCursor"
- scroll-mode="keep-visible"
- focus-on-move=""
- cursor-target-class="selected"
- ></gr-cursor-manager>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
index 80d8729..b8ba86c 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
@@ -16,7 +16,6 @@
*/
import '../../../test/common-test-setup-karma.js';
-import {listenOnce} from '../../../test/test-utils.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-file-list.js';
@@ -26,7 +25,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {runA11yAudit} from '../../../test/a11y-test-utils.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-import {TestKeyboardShortcutBinder, stubRestApi, spyRestApi} from '../../../test/test-utils.js';
+import {TestKeyboardShortcutBinder, stubRestApi, spyRestApi, listenOnce} from '../../../test/test-utils.js';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
import {createCommentThreads} from '../../../utils/comment-util.js';
import {createChangeComments} from '../../../test/test-data-generators.js';
@@ -80,19 +79,16 @@
suite('basic tests', () => {
setup(done => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
stubRestApi('getPreferences').returns(Promise.resolve({}));
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
stubRestApi('getAccountCapabilities').returns(Promise.resolve({}));
- stub('gr-date-formatter', {
- _loadTimeFormat() { return Promise.resolve(''); },
- });
- stub('gr-diff-host', {
- reload() { return Promise.resolve(); },
- prefetchDiff() {},
- });
+ stub('gr-date-formatter', '_loadTimeFormat').callsFake(() =>
+ Promise.resolve('')
+ );
+ stub('gr-diff-host', 'reload').callsFake(() => Promise.resolve());
+ stub('gr-diff-host', 'prefetchDiff').callsFake(() => {});
// Element must be wrapped in an element with direct access to the
// comment API.
@@ -484,7 +480,7 @@
patchNum: 2,
};
element.change = {_number: 42};
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.setCursorAtIndex(0);
});
test('toggle left diff via shortcut', () => {
@@ -502,38 +498,38 @@
flush();
const items = [...element.root.querySelectorAll('.file-row')];
- element.$.fileCursor.stops = items;
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.stops = items;
+ element.fileCursor.setCursorAtIndex(0);
assert.equal(items.length, 3);
assert.isTrue(items[0].classList.contains('selected'));
assert.isFalse(items[1].classList.contains('selected'));
assert.isFalse(items[2].classList.contains('selected'));
// j with a modifier should not move the cursor.
MockInteractions.pressAndReleaseKeyOn(element, 74, 'shift', 'j');
- assert.equal(element.$.fileCursor.index, 0);
+ assert.equal(element.fileCursor.index, 0);
// down should not move the cursor.
MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'down');
- assert.equal(element.$.fileCursor.index, 0);
+ assert.equal(element.fileCursor.index, 0);
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
- assert.equal(element.$.fileCursor.index, 1);
+ assert.equal(element.fileCursor.index, 1);
assert.equal(element.selectedIndex, 1);
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
const navStub = sinon.stub(GerritNav, 'navigateToDiff');
- assert.equal(element.$.fileCursor.index, 2);
+ assert.equal(element.fileCursor.index, 2);
assert.equal(element.selectedIndex, 2);
// k with a modifier should not move the cursor.
MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
- assert.equal(element.$.fileCursor.index, 2);
+ assert.equal(element.fileCursor.index, 2);
// up should not move the cursor.
MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'down');
- assert.equal(element.$.fileCursor.index, 2);
+ assert.equal(element.fileCursor.index, 2);
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
- assert.equal(element.$.fileCursor.index, 1);
+ assert.equal(element.fileCursor.index, 1);
assert.equal(element.selectedIndex, 1);
MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
@@ -544,7 +540,7 @@
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
- assert.equal(element.$.fileCursor.index, 0);
+ assert.equal(element.fileCursor.index, 0);
assert.equal(element.selectedIndex, 0);
const createCommentInPlaceStub = sinon.stub(element.$.diffCursor,
@@ -558,8 +554,8 @@
sinon.stub(element, '_expandedFilesChanged');
flush();
const files = [...element.root.querySelectorAll('.file-row')];
- element.$.fileCursor.stops = files;
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.stops = files;
+ element.fileCursor.setCursorAtIndex(0);
assert.equal(element.diffs.length, 0);
assert.equal(element._expandedFiles.length, 0);
@@ -575,7 +571,7 @@
assert.equal(element.diffs.length, 0);
assert.equal(element._expandedFiles.length, 0);
- element.$.fileCursor.setCursorAtIndex(1);
+ element.fileCursor.setCursorAtIndex(1);
MockInteractions.keyUpOn(element, 73, null, 'i');
flush();
assert.equal(element.diffs.length, 1);
@@ -702,7 +698,7 @@
basePatchNum: 'PARENT',
patchNum: 2,
};
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.setCursorAtIndex(0);
const reviewSpy = sinon.spy(element, '_reviewFile');
const toggleExpandSpy = sinon.spy(element, '_toggleFileExpanded');
@@ -808,7 +804,7 @@
basePatchNum: 'PARENT',
patchNum: 2,
};
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.setCursorAtIndex(0);
sinon.stub(element, '_expandedFilesChanged');
flush();
const fileRows =
@@ -836,7 +832,7 @@
patchNum: 2,
};
sinon.spy(element, '_updateDiffPreferences');
- element.$.fileCursor.setCursorAtIndex(0);
+ element.fileCursor.setCursorAtIndex(0);
flush();
// Tap on a file to generate the diff.
@@ -1105,13 +1101,13 @@
element.reload().then(() => {
assert.isFalse(element._loading);
- element.flushDebouncer('loading-change');
+ element.loadingTask.flush();
assert.isFalse(element.classList.contains('loading'));
done();
});
assert.isTrue(element._loading);
assert.isFalse(element.classList.contains('loading'));
- element.flushDebouncer('loading-change');
+ element.loadingTask.flush();
assert.isTrue(element.classList.contains('loading'));
});
@@ -1121,7 +1117,7 @@
element.patchRange = {patchNum: 12};
element.reload();
assert.isTrue(element._loading);
- element.flushDebouncer('loading-change');
+ element.loadingTask.flush();
assert.isFalse(element.classList.contains('loading'));
});
});
@@ -1411,13 +1407,11 @@
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
- stub('gr-date-formatter', {
- _loadTimeFormat() { return Promise.resolve(''); },
- });
- stub('gr-diff-host', {
- reload() { return Promise.resolve(); },
- prefetchDiff() {},
- });
+ stub('gr-date-formatter', '_loadTimeFormat').callsFake(() =>
+ Promise.resolve('')
+ );
+ stub('gr-diff-host', 'reload').callsFake(() => Promise.resolve());
+ stub('gr-diff-host', 'prefetchDiff').callsFake(() => {});
// Element must be wrapped in an element with direct access to the
// comment API.
@@ -1489,7 +1483,7 @@
assert.isFalse(diffStops[11].classList.contains('target-row'));
// The file cursor is now at 1.
- assert.equal(element.$.fileCursor.index, 1);
+ assert.equal(element.fileCursor.index, 1);
MockInteractions.keyUpOn(element, 73, null, 'i');
flush();
@@ -1531,7 +1525,7 @@
assert.isTrue(diffStops[11].classList.contains('target-row'));
// The file cursor is still at 0.
- assert.equal(element.$.fileCursor.index, 0);
+ assert.equal(element.fileCursor.index, 0);
});
suite('n key presses', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index b50bff4..c11e484 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -17,8 +17,6 @@
import '@polymer/iron-input/iron-input';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-included-in-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -31,9 +29,7 @@
}
@customElement('gr-included-in-dialog')
-export class GrIncludedInDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrIncludedInDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
index 2029209..83258c1b 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
@@ -65,6 +65,9 @@
.loading.loaded {
display: none;
}
+ .warning {
+ color: var(--warning-foreground);
+ }
</style>
<header>
<h1 id="title" class="heading-1">Included In:</h1>
@@ -86,6 +89,11 @@
</iron-input>
</header>
<div class$="[[_computeLoadingClass(_loaded)]]">Loading...</div>
+ <iron-icon icon="gr-icons:warning" class="warningBeforeSubmit"></iron-icon>
+ <span class="warning"
+ >The Inlcuded In button will be moved to the overflow menu on the top right
+ in 2 weeks.
+ </span>
<template
is="dom-repeat"
items="[[_computeGroups(_includedIn, _filterText)]]"
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
index 60a6058..b4fa4a8 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-button/gr-button';
import '../../../styles/gr-voting-styles';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-label-score-row_html';
import {customElement, property} from '@polymer/decorators';
@@ -56,9 +54,7 @@
}
@customElement('gr-label-score-row')
-export class GrLabelScoreRow extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelScoreRow extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
index 312532e..c53f386 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
@@ -62,12 +62,40 @@
}
gr-button.iron-selected[vote='positive'] {
--button-background-color: var(--vote-color-recommended);
+ --gr-button: {
+ padding: 0 var(--spacing-m);
+ border-style: solid;
+ border-color: var(--vote-outline-recommended);
+ border-top-left-radius: 1em;
+ border-top-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+ border-bottom-left-radius: 1em;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ color: var(--chip-color);
+ }
}
gr-button.iron-selected[vote='min'] {
--button-background-color: var(--vote-color-rejected);
}
gr-button.iron-selected[vote='negative'] {
--button-background-color: var(--vote-color-disliked);
+ --gr-button: {
+ padding: 0 var(--spacing-m);
+ border-style: solid;
+ border-color: var(--vote-outline-disliked);
+ border-top-left-radius: 1em;
+ border-top-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+ border-bottom-left-radius: 1em;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ color: var(--chip-color);
+ }
}
gr-button.iron-selected[vote='neutral'] {
--button-background-color: var(--vote-color-neutral);
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
index 661cd1a..4147cc0 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
@@ -16,8 +16,6 @@
*/
import '../gr-label-score-row/gr-label-score-row';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-label-scores_html';
import {customElement, property} from '@polymer/decorators';
@@ -38,11 +36,10 @@
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {appContext} from '../../../services/app-context';
import {labelCompare} from '../../../utils/label-util';
+import {Execution} from '../../../constants/reporting';
@customElement('gr-label-scores')
-export class GrLabelScores extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelScores extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -104,7 +101,10 @@
}
}
const stringVal = `${numberValue}`;
- this.reporting.reportExecution('label-value-not-found', {value: stringVal});
+ this.reporting.reportExecution(Execution.REACHABLE_CODE, {
+ value: stringVal,
+ id: 'label-value-not-found',
+ });
return stringVal;
}
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
index f913459..3ea9f68 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
@@ -23,8 +23,6 @@
import '../../shared/gr-formatted-text/gr-formatted-text';
import '../../../styles/shared-styles';
import '../../../styles/gr-voting-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-message_html';
import {MessageTag, SpecialFilePath} from '../../../constants/constants';
@@ -41,6 +39,7 @@
ChangeMessageId,
PatchSetNum,
AccountInfo,
+ BasePatchSetNum,
} from '../../../types/common';
import {CommentThread} from '../../../utils/comment-util';
import {hasOwnProperty} from '../../../utils/common-util';
@@ -69,7 +68,7 @@
id: ChangeMessageId;
}
-interface ChangeMessage extends ChangeMessageInfo {
+export interface ChangeMessage extends ChangeMessageInfo {
// TODO(TS): maybe should be an enum instead
type: string;
expanded: boolean;
@@ -84,9 +83,7 @@
}
@customElement('gr-message')
-export class GrMessage extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrMessage extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -199,13 +196,13 @@
private readonly restApiService = appContext.restApiService;
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('click', e => this._handleClick(e));
}
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.restApiService.getConfig().then(config => {
this.config = config;
});
@@ -306,7 +303,7 @@
const match = this.message.message.match(MERGED_PATCHSET_PATTERN)!;
if (isNaN(Number(match[1])))
throw new Error('invalid patchnum in message');
- basePatchNum = Number(match[1]) as PatchSetNum;
+ basePatchNum = Number(match[1]) as BasePatchSetNum;
patchNum = computeLatestPatchNum(computeAllPatchSets(this.change))!;
} else {
// Message is of the form "Commit Message was updated" or "Patchset X
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
index c018443..4a41316 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
@@ -170,15 +170,29 @@
}
.score.negative {
background-color: var(--vote-color-disliked);
+ border: 1px solid var(--vote-outline-disliked);
+ line-height: calc(var(--line-height-normal) - 2px);
+ color: var(--chip-color);
}
.score.negative.min {
background-color: var(--vote-color-rejected);
+ border: none;
+ padding-top: 1px;
+ padding-bottom: 1px;
+ color: var(--vote-text-color);
}
.score.positive {
background-color: var(--vote-color-recommended);
+ border: 1px solid var(--vote-outline-recommended);
+ line-height: calc(var(--line-height-normal) - 2px);
+ color: var(--chip-color);
}
.score.positive.max {
background-color: var(--vote-color-approved);
+ border: none;
+ padding-top: 1px;
+ padding-bottom: 1px;
+ color: var(--vote-text-color);
}
gr-account-label {
--gr-account-label-text-style: {
@@ -288,7 +302,8 @@
items="[[update.reviewers]]"
as="reviewer"
>
- <gr-account-chip account="[[reviewer]]"> </gr-account-chip>
+ <gr-account-chip account="[[reviewer]]" change="[[change]]">
+ </gr-account-chip>
</template>
</div>
</template>
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.js b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.js
deleted file mode 100644
index 3f4e13a..0000000
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.js
+++ /dev/null
@@ -1,577 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-message.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {createChange, createRevisions} from '../../../test/test-data-generators.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-message');
-
-suite('gr-message tests', () => {
- let element;
-
- suite('when admin and logged in', () => {
- setup(done => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
- stubRestApi('getPreferences').returns(Promise.resolve({}));
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('getIsAdmin').returns(Promise.resolve(true));
- stubRestApi('deleteChangeCommitMessage').returns(Promise.resolve({}));
- element = basicFixture.instantiate();
- flush(done);
- });
-
- test('reply event', done => {
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'Uploaded patch set 1.',
- _revision_number: 1,
- expanded: true,
- };
-
- element.addEventListener('reply', e => {
- assert.deepEqual(e.detail.message, element.message);
- done();
- });
- flush();
- assert.isFalse(
- element.shadowRoot.querySelector('.replyActionContainer').hidden
- );
- MockInteractions.tap(element.shadowRoot.querySelector('.replyBtn'));
- });
-
- test('can see delete button', () => {
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'Uploaded patch set 1.',
- _revision_number: 1,
- expanded: true,
- };
-
- flush();
- assert.isFalse(element.shadowRoot.querySelector('.deleteBtn').hidden);
- });
-
- test('delete change message', done => {
- element.changeNum = 314159;
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'Uploaded patch set 1.',
- _revision_number: 1,
- expanded: true,
- };
-
- element.addEventListener('change-message-deleted', e => {
- assert.deepEqual(e.detail.message, element.message);
- assert.isFalse(element.shadowRoot.querySelector('.deleteBtn').disabled);
- done();
- });
- flush();
- MockInteractions.tap(element.shadowRoot.querySelector('.deleteBtn'));
- assert.isTrue(element.shadowRoot.querySelector('.deleteBtn').disabled);
- });
-
- test('autogenerated prefix hiding', () => {
- element.message = {
- tag: 'autogenerated:gerrit:test',
- updated: '2016-01-12 20:24:49.448000000',
- expanded: false,
- };
-
- assert.isTrue(element.isAutomated);
- assert.isFalse(element.hidden);
-
- element.hideAutomated = true;
-
- assert.isTrue(element.hidden);
- });
-
- test('reviewer message treated as autogenerated', () => {
- element.message = {
- tag: 'autogenerated:gerrit:test',
- updated: '2016-01-12 20:24:49.448000000',
- reviewer: {},
- expanded: false,
- };
-
- assert.isTrue(element.isAutomated);
- assert.isFalse(element.hidden);
-
- element.hideAutomated = true;
-
- assert.isTrue(element.hidden);
- });
-
- test('batch reviewer message treated as autogenerated', () => {
- element.message = {
- type: 'REVIEWER_UPDATE',
- updated: '2016-01-12 20:24:49.448000000',
- reviewer: {},
- expanded: false,
- };
-
- assert.isTrue(element.isAutomated);
- assert.isFalse(element.hidden);
-
- element.hideAutomated = true;
-
- assert.isTrue(element.hidden);
- });
-
- test('tag that is not autogenerated prefix does not hide', () => {
- element.message = {
- tag: 'something',
- updated: '2016-01-12 20:24:49.448000000',
- expanded: false,
- };
-
- assert.isFalse(element.isAutomated);
- assert.isFalse(element.hidden);
-
- element.hideAutomated = true;
-
- assert.isFalse(element.hidden);
- });
-
- test('reply button hidden unless logged in', () => {
- const message = {
- message: 'Uploaded patch set 1.',
- expanded: false,
- };
- assert.isFalse(element._computeShowReplyButton(message, false));
- assert.isTrue(element._computeShowReplyButton(message, true));
- });
-
- test('_computeShowOnBehalfOf', () => {
- const message = {
- message: '...',
- expanded: false,
- };
- assert.isNotOk(element._computeShowOnBehalfOf(message));
- message.author = {_account_id: 1115495};
- assert.isNotOk(element._computeShowOnBehalfOf(message));
- message.real_author = {_account_id: 1115495};
- assert.isNotOk(element._computeShowOnBehalfOf(message));
- message.real_author._account_id = 123456;
- assert.isOk(element._computeShowOnBehalfOf(message));
- message.updated_by = message.author;
- delete message.author;
- assert.isOk(element._computeShowOnBehalfOf(message));
- delete message.updated_by;
- assert.isNotOk(element._computeShowOnBehalfOf(message));
- });
-
- ['Trybot-Ready', 'Tryjob-Request', 'Commit-Queue'].forEach(label => {
- test(`${label} ignored for color voting`, () => {
- element.message = {
- author: {},
- expanded: false,
- message: `Patch Set 1: ${label}+1`,
- };
- assert.isNotOk(
- element.root.querySelector('.negativeVote'));
- assert.isNotOk(
- element.root.querySelector('.positiveVote'));
- });
- });
-
- test('clicking on date link fires event', () => {
- element.message = {
- type: 'REVIEWER_UPDATE',
- updated: '2016-01-12 20:24:49.448000000',
- reviewer: {},
- id: '47c43261_55aa2c41',
- expanded: false,
- };
- flush();
- const stub = sinon.stub();
- element.addEventListener('message-anchor-tap', stub);
- const dateEl = element.shadowRoot
- .querySelector('.date');
- assert.ok(dateEl);
- MockInteractions.tap(dateEl);
-
- assert.isTrue(stub.called);
- assert.deepEqual(stub.lastCall.args[0].detail, {id: element.message.id});
- });
-
- suite('uploaded patchset X message navigates to X - 1 vs X', () => {
- let navStub;
- setup(() => {
- element.change = {...createChange(), revisions: createRevisions(4)};
- navStub = sinon.stub(GerritNav, 'navigateToChange');
- });
-
- test('Patchset 1 navigates to Base', () => {
- element.message = {
- message: 'Uploaded patch set 1.',
- };
- element._handleViewPatchsetDiff(new MouseEvent('click'));
- assert.isTrue(navStub.calledWithExactly(element.change, 1,
- 'PARENT'));
- });
-
- test('Patchset X navigates to X vs X - 1', () => {
- element.message = {
- message: 'Uploaded patch set 2.',
- };
- element._handleViewPatchsetDiff(new MouseEvent('click'));
- assert.isTrue(navStub.calledWithExactly(element.change, 2, 1));
-
- element.message = {
- message: 'Uploaded patch set 200.',
- };
- element._handleViewPatchsetDiff(new MouseEvent('click'));
- assert.isTrue(navStub.calledWithExactly(element.change, 200, 199));
- });
-
- test('Commit message updated', () => {
- element.message = {
- message: 'Commit message updated.',
- };
- element._handleViewPatchsetDiff(new MouseEvent('click'));
- assert.isTrue(navStub.calledWithExactly(element.change, 4, 3));
- });
-
- test('Merged patchset change message', () => {
- element.message = {
- message: 'abcd↵3 is the latest approved patch-set.↵abc',
- };
- element._handleViewPatchsetDiff(new MouseEvent('click'));
- assert.isTrue(navStub.calledWithExactly(element.change, 4, 3));
- });
- });
-
- suite('compute messages', () => {
- test('empty', () => {
- assert.equal(element._computeMessageContent(true, '', ''), '');
- assert.equal(element._computeMessageContent(false, '', ''), '');
- });
-
- test('new patchset', () => {
- const original = 'Uploaded patch set 1.';
- const tag = 'autogenerated:gerrit:newPatchSet';
- let actual = element._computeMessageContent(true, original, tag);
- assert.equal(actual, element._computeMessageContentCollapsed(
- original, tag, []));
- assert.equal(actual, original);
- actual = element._computeMessageContent(false, original, tag);
- assert.equal(actual, original);
- });
-
- test('new patchset rebased', () => {
- const original = 'Patch Set 27: Patch Set 26 was rebased';
- const tag = 'autogenerated:gerrit:newPatchSet';
- const expected = 'Patch Set 26 was rebased';
- let actual = element._computeMessageContent(true, original, tag);
- assert.equal(actual, expected);
- assert.equal(actual, element._computeMessageContentCollapsed(
- original, tag, []));
- actual = element._computeMessageContent(false, original, tag);
- assert.equal(actual, expected);
- });
-
- test('ready for review', () => {
- const original = 'Patch Set 1:\n\nThis change is ready for review.';
- const tag = undefined;
- const expected = 'This change is ready for review.';
- let actual = element._computeMessageContent(true, original, tag);
- assert.equal(actual, expected);
- assert.equal(actual, element._computeMessageContentCollapsed(
- original, tag, []));
- actual = element._computeMessageContent(false, original, tag);
- assert.equal(actual, expected);
- });
-
- test('vote', () => {
- const original = 'Patch Set 1: Code-Style+1';
- const tag = undefined;
- const expected = '';
- let actual = element._computeMessageContent(true, original, tag);
- assert.equal(actual, expected);
- actual = element._computeMessageContent(false, original, tag);
- assert.equal(actual, expected);
- });
-
- test('comments', () => {
- const original = 'Patch Set 1:\n\n(3 comments)';
- const tag = undefined;
- const expected = '';
- let actual = element._computeMessageContent(true, original, tag);
- assert.equal(actual, expected);
- actual = element._computeMessageContent(false, original, tag);
- assert.equal(actual, expected);
- });
- });
-
- test('votes', () => {
- element.message = {
- author: {},
- expanded: false,
- message: 'Patch Set 1: Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
- };
- element.labelExtremes = {
- 'Verified': {max: 1, min: -1},
- 'Code-Review': {max: 2, min: -2},
- 'Trybot-Label3': {max: 3, min: 0},
- };
- flush();
- const scoreChips = element.root.querySelectorAll('.score');
- assert.equal(scoreChips.length, 3);
-
- assert.isTrue(scoreChips[0].classList.contains('positive'));
- assert.isTrue(scoreChips[0].classList.contains('max'));
-
- assert.isTrue(scoreChips[1].classList.contains('negative'));
- assert.isTrue(scoreChips[1].classList.contains('min'));
-
- assert.isTrue(scoreChips[2].classList.contains('positive'));
- assert.isFalse(scoreChips[2].classList.contains('min'));
- });
-
- test('Uploaded patch set X', () => {
- element.message = {
- author: {},
- expanded: false,
- message: 'Uploaded patch set 1:' +
- 'Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
- };
- element.labelExtremes = {
- 'Verified': {max: 1, min: -1},
- 'Code-Review': {max: 2, min: -2},
- 'Trybot-Label3': {max: 3, min: 0},
- };
- flush();
- const scoreChips = element.root.querySelectorAll('.score');
- assert.equal(scoreChips.length, 3);
-
- assert.isTrue(scoreChips[0].classList.contains('positive'));
- assert.isTrue(scoreChips[0].classList.contains('max'));
-
- assert.isTrue(scoreChips[1].classList.contains('negative'));
- assert.isTrue(scoreChips[1].classList.contains('min'));
-
- assert.isTrue(scoreChips[2].classList.contains('positive'));
- assert.isFalse(scoreChips[2].classList.contains('min'));
- });
-
- test('removed votes', () => {
- element.message = {
- author: {},
- expanded: false,
- message: 'Patch Set 1: Verified+1 -Code-Review -Commit-Queue',
- };
- element.labelExtremes = {
- 'Verified': {max: 1, min: -1},
- 'Code-Review': {max: 2, min: -2},
- 'Commit-Queue': {max: 3, min: 0},
- };
- flush();
- const scoreChips = element.root.querySelectorAll('.score');
- assert.equal(scoreChips.length, 3);
-
- assert.isTrue(scoreChips[1].classList.contains('removed'));
- assert.isTrue(scoreChips[2].classList.contains('removed'));
- });
-
- test('false negative vote', () => {
- element.message = {
- author: {},
- expanded: false,
- message: 'Patch Set 1: Cherry Picked from branch stable-2.14.',
- };
- element.labelExtremes = {};
- const scoreChips = element.root.querySelectorAll('.score');
- assert.equal(scoreChips.length, 0);
- });
- });
-
- suite('when not logged in', () => {
- setup(done => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(false));
- stubRestApi('getPreferences').returns(Promise.resolve({}));
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('getIsAdmin').returns(Promise.resolve(false));
- stubRestApi('deleteChangeCommitMessage').returns(Promise.resolve({}));
- element = basicFixture.instantiate();
- flush(done);
- });
-
- test('reply and delete button should be hidden', () => {
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'Uploaded patch set 1.',
- _revision_number: 1,
- expanded: true,
- };
-
- flush();
- assert.isTrue(
- element.shadowRoot.querySelector('.replyActionContainer').hidden
- );
- assert.isTrue(
- element.shadowRoot.querySelector('.deleteBtn').hidden
- );
- });
- });
-
- suite('patchset comment summary', () => {
- setup(() => {
- element = basicFixture.instantiate();
- element.message = {id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3'};
- });
-
- test('single patchset comment posted', () => {
- const threads = [{
- comments: [{
- 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._computeMessageContentCollapsed(
- '', undefined, threads), 'testing the load');
- assert.equal(element._computeMessageContent(false, '', undefined), '');
- });
-
- test('single patchset comment with reply', () => {
- const threads = [{
- comments: [{
- 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,
- }, {
- 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._computeMessageContentCollapsed(
- '', undefined, threads), 'n');
- assert.equal(element._computeMessageContent(false, '', undefined), '');
- });
- });
-
- suite('when logged in but not admin', () => {
- setup(async () => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('getIsAdmin').returns(Promise.resolve(false));
- stubRestApi('deleteChangeCommitMessage').returns(Promise.resolve({}));
- element = basicFixture.instantiate();
- await flush();
- });
-
- test('can see reply but not delete button', () => {
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'Uploaded patch set 1.',
- _revision_number: 1,
- expanded: true,
- };
-
- flush();
- assert.isFalse(
- element.shadowRoot.querySelector('.replyActionContainer').hidden
- );
- assert.isTrue(
- element.shadowRoot.querySelector('.deleteBtn').hidden
- );
- });
-
- test('reply button shown when message is updated', () => {
- element.message = undefined;
- flush();
- let replyEl = element.shadowRoot.querySelector('.replyActionContainer');
- // We don't even expect the button to show up in the DOM when the message
- // is undefined.
- assert.isNotOk(replyEl);
-
- element.message = {
- id: '47c43261_55aa2c41',
- author: {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- },
- date: '2016-01-12 20:24:49.448000000',
- message: 'not empty',
- _revision_number: 1,
- expanded: true,
- };
- flush();
- replyEl = element.shadowRoot.querySelector('.replyActionContainer');
- assert.isOk(replyEl);
- assert.isFalse(replyEl.hidden);
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts
new file mode 100644
index 0000000..b8f3c73
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts
@@ -0,0 +1,676 @@
+/**
+ * @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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-message';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {
+ createChange,
+ createChangeMessage,
+ createComment,
+ createRevisions,
+} from '../../../test/test-data-generators';
+import {
+ query,
+ queryAll,
+ queryAndAssert,
+ stubRestApi,
+} from '../../../test/test-utils';
+import {GrMessage} from './gr-message';
+import {
+ AccountId,
+ BasePatchSetNum,
+ ChangeMessageId,
+ EmailAddress,
+ NumericChangeId,
+ PatchSetNum,
+ ReviewInputTag,
+ Timestamp,
+ UrlEncodedCommentId,
+} from '../../../types/common';
+import {tap} from '@polymer/iron-test-helpers/mock-interactions';
+import {
+ ChangeMessageDeletedEventDetail,
+ ReplyEventDetail,
+} from '../../../types/events';
+import {GrButton} from '../../shared/gr-button/gr-button';
+import {CommentSide} from '../../../constants/constants';
+import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+
+const basicFixture = fixtureFromElement('gr-message');
+
+suite('gr-message tests', () => {
+ let element: GrMessage;
+
+ suite('when admin and logged in', () => {
+ setup(done => {
+ stubRestApi('getIsAdmin').returns(Promise.resolve(true));
+ element = basicFixture.instantiate();
+ flush(done);
+ });
+
+ test('reply event', done => {
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'Uploaded patch set 1.',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+
+ element.addEventListener('reply', (e: CustomEvent<ReplyEventDetail>) => {
+ assert.deepEqual(e.detail.message, element.message);
+ done();
+ });
+ flush();
+ assert.isFalse(
+ queryAndAssert<HTMLElement>(element, '.replyActionContainer').hidden
+ );
+ tap(queryAndAssert(element, '.replyBtn'));
+ });
+
+ test('can see delete button', () => {
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'Uploaded patch set 1.',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+
+ flush();
+ assert.isFalse(queryAndAssert<HTMLElement>(element, '.deleteBtn').hidden);
+ });
+
+ test('delete change message', done => {
+ element.changeNum = 314159 as NumericChangeId;
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'Uploaded patch set 1.',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+
+ element.addEventListener(
+ 'change-message-deleted',
+ (e: CustomEvent<ChangeMessageDeletedEventDetail>) => {
+ assert.deepEqual(e.detail.message, element.message);
+ assert.isFalse(
+ (queryAndAssert(element, '.deleteBtn') as GrButton).disabled
+ );
+ done();
+ }
+ );
+ flush();
+ tap(queryAndAssert(element, '.deleteBtn'));
+ assert.isTrue(
+ (queryAndAssert(element, '.deleteBtn') as GrButton).disabled
+ );
+ });
+
+ test('autogenerated prefix hiding', () => {
+ element.message = {
+ ...createChangeMessage(),
+ tag: 'autogenerated:gerrit:test' as ReviewInputTag,
+ expanded: false,
+ };
+
+ assert.isTrue(element.isAutomated);
+ assert.isFalse(element.hidden);
+
+ element.hideAutomated = true;
+
+ assert.isTrue(element.hidden);
+ });
+
+ test('reviewer message treated as autogenerated', () => {
+ element.message = {
+ ...createChangeMessage(),
+ tag: 'autogenerated:gerrit:test' as ReviewInputTag,
+ reviewer: {},
+ expanded: false,
+ };
+
+ assert.isTrue(element.isAutomated);
+ assert.isFalse(element.hidden);
+
+ element.hideAutomated = true;
+
+ assert.isTrue(element.hidden);
+ });
+
+ test('batch reviewer message treated as autogenerated', () => {
+ element.message = {
+ ...createChangeMessage(),
+ type: 'REVIEWER_UPDATE',
+ reviewer: {},
+ expanded: false,
+ };
+
+ assert.isTrue(element.isAutomated);
+ assert.isFalse(element.hidden);
+
+ element.hideAutomated = true;
+
+ assert.isTrue(element.hidden);
+ });
+
+ test('tag that is not autogenerated prefix does not hide', () => {
+ element.message = {
+ ...createChangeMessage(),
+ tag: 'something' as ReviewInputTag,
+ expanded: false,
+ };
+
+ assert.isFalse(element.isAutomated);
+ assert.isFalse(element.hidden);
+
+ element.hideAutomated = true;
+
+ assert.isFalse(element.hidden);
+ });
+
+ test('reply button hidden unless logged in', () => {
+ const message = {
+ ...createChangeMessage(),
+ message: 'Uploaded patch set 1.',
+ expanded: false,
+ };
+ assert.isFalse(element._computeShowReplyButton(message, false));
+ assert.isTrue(element._computeShowReplyButton(message, true));
+ });
+
+ test('_computeShowOnBehalfOf', () => {
+ const message = {
+ ...createChangeMessage(),
+ message: '...',
+ expanded: false,
+ };
+ assert.isNotOk(element._computeShowOnBehalfOf(message));
+ message.author = {_account_id: 1115495 as AccountId};
+ assert.isNotOk(element._computeShowOnBehalfOf(message));
+ message.real_author = {_account_id: 1115495 as AccountId};
+ assert.isNotOk(element._computeShowOnBehalfOf(message));
+ message.real_author._account_id = 123456 as AccountId;
+ assert.isOk(element._computeShowOnBehalfOf(message));
+ message.updated_by = message.author;
+ delete message.author;
+ assert.isOk(element._computeShowOnBehalfOf(message));
+ delete message.updated_by;
+ assert.isNotOk(element._computeShowOnBehalfOf(message));
+ });
+
+ ['Trybot-Ready', 'Tryjob-Request', 'Commit-Queue'].forEach(label => {
+ test(`${label} ignored for color voting`, () => {
+ element.message = {
+ ...createChangeMessage(),
+ author: {},
+ expanded: false,
+ message: `Patch Set 1: ${label}+1`,
+ };
+ assert.isNotOk(query(element, '.negativeVote'));
+ assert.isNotOk(query(element, '.positiveVote'));
+ });
+ });
+
+ test('clicking on date link fires event', () => {
+ element.message = {
+ ...createChangeMessage(),
+ type: 'REVIEWER_UPDATE',
+ reviewer: {},
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ expanded: false,
+ };
+ flush();
+ const stub = sinon.stub();
+ element.addEventListener('message-anchor-tap', stub);
+ const dateEl = queryAndAssert(element, '.date');
+ assert.ok(dateEl);
+ tap(dateEl);
+
+ assert.isTrue(stub.called);
+ assert.deepEqual(stub.lastCall.args[0].detail, {id: element.message.id});
+ });
+
+ suite('uploaded patchset X message navigates to X - 1 vs X', () => {
+ let navStub: SinonStubbedMember<typeof GerritNav.navigateToChange>;
+ setup(() => {
+ element.change = {...createChange(), revisions: createRevisions(4)};
+ navStub = sinon.stub(GerritNav, 'navigateToChange');
+ });
+
+ test('Patchset 1 navigates to Base', () => {
+ element.message = {
+ ...createChangeMessage(),
+ message: 'Uploaded patch set 1.',
+ };
+ element._handleViewPatchsetDiff(new MouseEvent('click'));
+ assert.isTrue(
+ navStub.calledWithExactly(
+ element.change!,
+ 1 as PatchSetNum,
+ 'PARENT' as BasePatchSetNum
+ )
+ );
+ });
+
+ test('Patchset X navigates to X vs X - 1', () => {
+ element.message = {
+ ...createChangeMessage(),
+ message: 'Uploaded patch set 2.',
+ };
+ element._handleViewPatchsetDiff(new MouseEvent('click'));
+ assert.isTrue(
+ navStub.calledWithExactly(
+ element.change!,
+ 2 as PatchSetNum,
+ 1 as BasePatchSetNum
+ )
+ );
+
+ element.message = {
+ ...createChangeMessage(),
+ message: 'Uploaded patch set 200.',
+ };
+ element._handleViewPatchsetDiff(new MouseEvent('click'));
+ assert.isTrue(
+ navStub.calledWithExactly(
+ element.change!,
+ 200 as PatchSetNum,
+ 199 as BasePatchSetNum
+ )
+ );
+ });
+
+ test('Commit message updated', () => {
+ element.message = {
+ ...createChangeMessage(),
+ message: 'Commit message updated.',
+ };
+ element._handleViewPatchsetDiff(new MouseEvent('click'));
+ assert.isTrue(
+ navStub.calledWithExactly(
+ element.change!,
+ 4 as PatchSetNum,
+ 3 as BasePatchSetNum
+ )
+ );
+ });
+
+ test('Merged patchset change message', () => {
+ element.message = {
+ ...createChangeMessage(),
+ message: 'abcd↵3 is the latest approved patch-set.↵abc',
+ };
+ element._handleViewPatchsetDiff(new MouseEvent('click'));
+ assert.isTrue(
+ navStub.calledWithExactly(
+ element.change!,
+ 4 as PatchSetNum,
+ 3 as BasePatchSetNum
+ )
+ );
+ });
+ });
+
+ suite('compute messages', () => {
+ test('empty', () => {
+ assert.equal(
+ element._computeMessageContent(true, '', '' as ReviewInputTag),
+ ''
+ );
+ assert.equal(
+ element._computeMessageContent(false, '', '' as ReviewInputTag),
+ ''
+ );
+ });
+
+ test('new patchset', () => {
+ const original = 'Uploaded patch set 1.';
+ const tag = 'autogenerated:gerrit:newPatchSet' as ReviewInputTag;
+ let actual = element._computeMessageContent(true, original, tag);
+ assert.equal(
+ actual,
+ element._computeMessageContentCollapsed(original, tag, [])
+ );
+ assert.equal(actual, original);
+ actual = element._computeMessageContent(false, original, tag);
+ assert.equal(actual, original);
+ });
+
+ test('new patchset rebased', () => {
+ const original = 'Patch Set 27: Patch Set 26 was rebased';
+ const tag = 'autogenerated:gerrit:newPatchSet' as ReviewInputTag;
+ const expected = 'Patch Set 26 was rebased';
+ let actual = element._computeMessageContent(true, original, tag);
+ assert.equal(actual, expected);
+ assert.equal(
+ actual,
+ element._computeMessageContentCollapsed(original, tag, [])
+ );
+ actual = element._computeMessageContent(false, original, tag);
+ assert.equal(actual, expected);
+ });
+
+ test('ready for review', () => {
+ const original = 'Patch Set 1:\n\nThis change is ready for review.';
+ const tag = undefined;
+ const expected = 'This change is ready for review.';
+ let actual = element._computeMessageContent(true, original, tag);
+ assert.equal(actual, expected);
+ assert.equal(
+ actual,
+ element._computeMessageContentCollapsed(original, tag, [])
+ );
+ actual = element._computeMessageContent(false, original, tag);
+ assert.equal(actual, expected);
+ });
+
+ test('vote', () => {
+ const original = 'Patch Set 1: Code-Style+1';
+ const tag = undefined;
+ const expected = '';
+ let actual = element._computeMessageContent(true, original, tag);
+ assert.equal(actual, expected);
+ actual = element._computeMessageContent(false, original, tag);
+ assert.equal(actual, expected);
+ });
+
+ test('comments', () => {
+ const original = 'Patch Set 1:\n\n(3 comments)';
+ const tag = undefined;
+ const expected = '';
+ let actual = element._computeMessageContent(true, original, tag);
+ assert.equal(actual, expected);
+ actual = element._computeMessageContent(false, original, tag);
+ assert.equal(actual, expected);
+ });
+ });
+
+ test('votes', () => {
+ element.message = {
+ ...createChangeMessage(),
+ author: {},
+ expanded: false,
+ message: 'Patch Set 1: Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
+ };
+ element.labelExtremes = {
+ Verified: {max: 1, min: -1},
+ 'Code-Review': {max: 2, min: -2},
+ 'Trybot-Label3': {max: 3, min: 0},
+ };
+ flush();
+ const scoreChips = queryAll(element, '.score');
+ assert.equal(scoreChips.length, 3);
+
+ assert.isTrue(scoreChips[0].classList.contains('positive'));
+ assert.isTrue(scoreChips[0].classList.contains('max'));
+
+ assert.isTrue(scoreChips[1].classList.contains('negative'));
+ assert.isTrue(scoreChips[1].classList.contains('min'));
+
+ assert.isTrue(scoreChips[2].classList.contains('positive'));
+ assert.isFalse(scoreChips[2].classList.contains('min'));
+ });
+
+ test('Uploaded patch set X', () => {
+ element.message = {
+ ...createChangeMessage(),
+ author: {},
+ expanded: false,
+ message:
+ 'Uploaded patch set 1:' +
+ 'Verified+1 Code-Review-2 Trybot-Label3+1 Blub+1',
+ };
+ element.labelExtremes = {
+ Verified: {max: 1, min: -1},
+ 'Code-Review': {max: 2, min: -2},
+ 'Trybot-Label3': {max: 3, min: 0},
+ };
+ flush();
+ const scoreChips = queryAll(element, '.score');
+ assert.equal(scoreChips.length, 3);
+
+ assert.isTrue(scoreChips[0].classList.contains('positive'));
+ assert.isTrue(scoreChips[0].classList.contains('max'));
+
+ assert.isTrue(scoreChips[1].classList.contains('negative'));
+ assert.isTrue(scoreChips[1].classList.contains('min'));
+
+ assert.isTrue(scoreChips[2].classList.contains('positive'));
+ assert.isFalse(scoreChips[2].classList.contains('min'));
+ });
+
+ test('removed votes', () => {
+ element.message = {
+ ...createChangeMessage(),
+ author: {},
+ expanded: false,
+ message: 'Patch Set 1: Verified+1 -Code-Review -Commit-Queue',
+ };
+ element.labelExtremes = {
+ Verified: {max: 1, min: -1},
+ 'Code-Review': {max: 2, min: -2},
+ 'Commit-Queue': {max: 3, min: 0},
+ };
+ flush();
+ const scoreChips = queryAll(element, '.score');
+ assert.equal(scoreChips.length, 3);
+
+ assert.isTrue(scoreChips[1].classList.contains('removed'));
+ assert.isTrue(scoreChips[2].classList.contains('removed'));
+ });
+
+ test('false negative vote', () => {
+ element.message = {
+ ...createChangeMessage(),
+ author: {},
+ expanded: false,
+ message: 'Patch Set 1: Cherry Picked from branch stable-2.14.',
+ };
+ element.labelExtremes = {};
+ const scoreChips = element.root!.querySelectorAll('.score');
+ assert.equal(scoreChips.length, 0);
+ });
+ });
+
+ suite('when not logged in', () => {
+ setup(done => {
+ stubRestApi('getLoggedIn').returns(Promise.resolve(false));
+ stubRestApi('getIsAdmin').returns(Promise.resolve(false));
+ element = basicFixture.instantiate();
+ flush(done);
+ });
+
+ test('reply and delete button should be hidden', () => {
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'Uploaded patch set 1.',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+
+ flush();
+ assert.isTrue(
+ queryAndAssert<HTMLElement>(element, '.replyActionContainer').hidden
+ );
+ assert.isTrue(queryAndAssert<HTMLElement>(element, '.deleteBtn').hidden);
+ });
+ });
+
+ suite('patchset comment summary', () => {
+ setup(() => {
+ element = basicFixture.instantiate();
+ element.message = {
+ ...createChangeMessage(),
+ id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3' as ChangeMessageId,
+ };
+ });
+
+ test('single patchset comment posted', () => {
+ const threads = [
+ {
+ comments: [
+ {
+ ...createComment(),
+ change_message_id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3' as ChangeMessageId,
+ patch_set: 1 as PatchSetNum,
+ id: 'e365b138_bed65caa' as UrlEncodedCommentId,
+ updated: '2020-05-15 13:35:56.000000000' as Timestamp,
+ message: 'testing the load',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ collapsed: false,
+ },
+ ],
+ patchNum: 1 as PatchSetNum,
+ path: '/PATCHSET_LEVEL',
+ rootId: 'e365b138_bed65caa' as UrlEncodedCommentId,
+ commentSide: CommentSide.REVISION,
+ },
+ ];
+ assert.equal(
+ element._computeMessageContentCollapsed('', undefined, threads),
+ 'testing the load'
+ );
+ assert.equal(element._computeMessageContent(false, '', undefined), '');
+ });
+
+ test('single patchset comment with reply', () => {
+ const threads = [
+ {
+ comments: [
+ {
+ ...createComment(),
+ patch_set: 1 as PatchSetNum,
+ id: 'e365b138_bed65caa' as UrlEncodedCommentId,
+ updated: '2020-05-15 13:35:56.000000000' as Timestamp,
+ message: 'testing the load',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ collapsed: false,
+ },
+ {
+ change_message_id: '6a07f64a82f96e7337ca5f7f84cfc73abf8ac2a3',
+ patch_set: 1 as PatchSetNum,
+ id: 'd6efcc85_4cbbb6f4' as UrlEncodedCommentId,
+ in_reply_to: 'e365b138_bed65caa' as UrlEncodedCommentId,
+ updated: '2020-05-15 16:55:28.000000000' as Timestamp,
+ message: 'n',
+ unresolved: false,
+ path: '/PATCHSET_LEVEL',
+ __draft: true,
+ collapsed: true,
+ },
+ ],
+ patchNum: 1 as PatchSetNum,
+ path: '/PATCHSET_LEVEL',
+ rootId: 'e365b138_bed65caa' as UrlEncodedCommentId,
+ commentSide: CommentSide.REVISION,
+ },
+ ];
+ assert.equal(
+ element._computeMessageContentCollapsed('', undefined, threads),
+ 'n'
+ );
+ assert.equal(element._computeMessageContent(false, '', undefined), '');
+ });
+ });
+
+ suite('when logged in but not admin', () => {
+ setup(async () => {
+ stubRestApi('getIsAdmin').returns(Promise.resolve(false));
+ element = basicFixture.instantiate();
+ await flush();
+ });
+
+ test('can see reply but not delete button', () => {
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'Uploaded patch set 1.',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+
+ flush();
+ assert.isFalse(
+ queryAndAssert<HTMLElement>(element, '.replyActionContainer').hidden
+ );
+ assert.isTrue(queryAndAssert<HTMLElement>(element, '.deleteBtn').hidden);
+ });
+
+ test('reply button shown when message is updated', () => {
+ element.message = undefined;
+ flush();
+ let replyEl = query(element, '.replyActionContainer');
+ // We don't even expect the button to show up in the DOM when the message
+ // is undefined.
+ assert.isNotOk(replyEl);
+
+ element.message = {
+ ...createChangeMessage(),
+ id: '47c43261_55aa2c41' as ChangeMessageId,
+ author: {
+ _account_id: 1115495 as AccountId,
+ name: 'Andrew Bonventre',
+ email: 'andybons@chromium.org' as EmailAddress,
+ },
+ date: '2016-01-12 20:24:49.448000000' as Timestamp,
+ message: 'not empty',
+ _revision_number: 1 as PatchSetNum,
+ expanded: true,
+ };
+ flush();
+ replyEl = queryAndAssert(element, '.replyActionContainer');
+ assert.isOk(replyEl);
+ assert.isFalse((replyEl as HTMLElement).hidden);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
index bc3f167..6be0c07 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-icons/gr-icons';
import '../gr-message/gr-message';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-messages-list_html';
import {
@@ -213,9 +211,7 @@
}
@customElement('gr-messages-list')
-export class GrMessagesList extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrMessagesList extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
index 6c786ef..8fa8eab 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
@@ -62,7 +62,7 @@
checked="{{_showAllActivity}}"
aria-labelledby="showAllEntriesLabel"
role="switch"
- on-tap="_onTapShowAllActivityToggle"
+ on-click="_onTapShowAllActivityToggle"
></paper-toggle-button>
<div id="showAllEntriesLabel" aria-hidden="true">
<span>Show all entries</span>
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.js
index d22c7d0..fd45eec 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.js
@@ -133,7 +133,6 @@
suite('basic tests', () => {
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
stubRestApi('getDiffComments').returns(Promise.resolve(comments));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
@@ -440,7 +439,6 @@
let commentApiWrapper;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts
index 7b698f1..49c2486 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-change.ts
@@ -35,9 +35,6 @@
href?: string;
@property()
- isCurrentChange = false;
-
- @property()
showSubmittableCheck = false;
@property()
@@ -102,9 +99,6 @@
.submittableCheck.submittable {
display: inline;
}
- .arrowToCurrentChange {
- position: absolute;
- }
`,
];
}
@@ -113,13 +107,7 @@
const change = this.change;
if (!change) throw new Error('Missing change');
const linkClass = this._computeLinkClass(change);
- return html`<span
- role="img"
- class="arrowToCurrentChange"
- aria-label="Arrow marking current change"
- ?hidden=${!this.isCurrentChange}
- >âž”</span
- >
+ return html`
<div class="changeContainer">
<a href="${this.href}" class="${linkClass}"><slot></slot></a>
${this.showSubmittableCheck
@@ -137,7 +125,8 @@
(${this._computeChangeStatus(change)})
</span>`
: ''}
- </div> `;
+ </div>
+ `;
}
_computeLinkClass(change: ChangeInfo | RelatedChangeAndCommitInfo) {
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
index 214271af..c75b8c4 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental.ts
@@ -21,7 +21,13 @@
import '../../plugins/gr-endpoint-slot/gr-endpoint-slot';
import {classMap} from 'lit-html/directives/class-map';
import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property, css, internalProperty} from 'lit-element';
+import {
+ customElement,
+ property,
+ css,
+ internalProperty,
+ TemplateResult,
+} from 'lit-element';
import {sharedStyles} from '../../../styles/shared-styles';
import {
SubmittedTogetherInfo,
@@ -42,7 +48,22 @@
} from '../../../utils/change-util';
/** What is the maximum number of shown changes in collapsed list? */
-const MAX_CHANGES_WHEN_COLLAPSED = 3;
+const DEFALT_NUM_CHANGES_WHEN_COLLAPSED = 3;
+
+export interface ChangeMarkersInList {
+ showCurrentChangeArrow: boolean;
+ showWhenCollapsed: boolean;
+ showTopArrow: boolean;
+ showBottomArrow: boolean;
+}
+
+export enum Section {
+ RELATED_CHANGES = 'related changes',
+ SUBMITTED_TOGETHER = 'submitted together',
+ SAME_TOPIC = 'same topic',
+ MERGE_CONFLICTS = 'merge conflicts',
+ CHERRY_PICKS = 'cherry picks',
+}
@customElement('gr-related-changes-list-experimental')
export class GrRelatedChangesListExperimental extends GrLitElement {
@@ -84,51 +105,77 @@
margin-left: 1.2em;
}
section {
- margin-bottom: var(--spacing-m);
+ margin-bottom: var(--spacing-l);
+ }
+ gr-related-change {
+ display: flex;
+ }
+ .marker {
+ position: absolute;
+ margin-left: calc(-1 * var(--spacing-s));
+ }
+ .arrowToCurrentChange {
+ position: absolute;
}
`,
];
}
render() {
- let showWhenCollapsedPredicate = this.showWhenCollapsedPredicateFactory(
+ const sectionSize = this.sectionSizeFactory(
+ this.relatedChanges.length,
+ this.submittedTogether?.changes.length || 0,
+ this.sameTopicChanges.length,
+ this.conflictingChanges.length,
+ this.cherryPickChanges.length
+ );
+ const relatedChangesMarkersPredicate = this.markersPredicateFactory(
this.relatedChanges.length,
this.relatedChanges.findIndex(relatedChange =>
this._changesEqual(relatedChange, this.change)
- )
+ ),
+ sectionSize(Section.RELATED_CHANGES)
);
const connectedRevisions = this._computeConnectedRevisions(
this.change,
this.patchNum,
this.relatedChanges
);
+ let firstNonEmptySectionFound = false;
+ let isFirstNonEmpty =
+ !firstNonEmptySectionFound && !!this.relatedChanges.length;
+ firstNonEmptySectionFound = firstNonEmptySectionFound || isFirstNonEmpty;
const relatedChangeSection = html` <section
- class="relatedChanges"
+ id="relatedChanges"
?hidden=${!this.relatedChanges.length}
>
<gr-related-collapse
title="Relation chain"
+ class="${classMap({first: isFirstNonEmpty})}"
.length=${this.relatedChanges.length}
+ .numChangesWhenCollapsed=${sectionSize(Section.RELATED_CHANGES)}
>
${this.relatedChanges.map(
(change, index) =>
- html`<gr-related-change
- class="${classMap({
- ['show-when-collapsed']: showWhenCollapsedPredicate(index),
- })}"
- .isCurrentChange="${this._changesEqual(change, this.change)}"
- .change="${change}"
- .connectedRevisions="${connectedRevisions}"
- .href="${change?._change_number
- ? GerritNav.getUrlForChangeById(
- change._change_number,
- change.project,
- change._revision_number as PatchSetNum
- )
- : ''}"
- .showChangeStatus=${true}
- >${change.commit.subject}</gr-related-change
- >`
+ html`${this.renderMarkers(
+ relatedChangesMarkersPredicate(index)
+ )}<gr-related-change
+ class="${classMap({
+ ['show-when-collapsed']: relatedChangesMarkersPredicate(index)
+ .showWhenCollapsed,
+ })}"
+ .change="${change}"
+ .connectedRevisions="${connectedRevisions}"
+ .href="${change?._change_number
+ ? GerritNav.getUrlForChangeById(
+ change._change_number,
+ change.project,
+ change._revision_number as PatchSetNum
+ )
+ : ''}"
+ .showChangeStatus=${true}
+ >${change.commit.subject}</gr-related-change
+ >`
)}
</gr-related-collapse>
</section>`;
@@ -136,12 +183,18 @@
const submittedTogetherChanges = this.submittedTogether?.changes ?? [];
const countNonVisibleChanges =
this.submittedTogether?.non_visible_changes ?? 0;
- showWhenCollapsedPredicate = this.showWhenCollapsedPredicateFactory(
+ const submittedTogetherMarkersPredicate = this.markersPredicateFactory(
submittedTogetherChanges.length,
submittedTogetherChanges.findIndex(relatedChange =>
this._changesEqual(relatedChange, this.change)
- )
+ ),
+ sectionSize(Section.SUBMITTED_TOGETHER)
);
+ isFirstNonEmpty =
+ !firstNonEmptySectionFound &&
+ (!!submittedTogetherChanges?.length ||
+ !!this.submittedTogether?.non_visible_changes);
+ firstNonEmptySectionFound = firstNonEmptySectionFound || isFirstNonEmpty;
const submittedTogetherSection = html`<section
id="submittedTogether"
?hidden=${!submittedTogetherChanges?.length &&
@@ -149,24 +202,29 @@
>
<gr-related-collapse
title="Submitted together"
+ class="${classMap({first: isFirstNonEmpty})}"
.length=${submittedTogetherChanges.length}
+ .numChangesWhenCollapsed=${sectionSize(Section.SUBMITTED_TOGETHER)}
>
${submittedTogetherChanges.map(
(change, index) =>
- html`<gr-related-change
- class="${classMap({
- ['show-when-collapsed']: showWhenCollapsedPredicate(index),
- })}"
- .isCurrentChange="${this._changesEqual(change, this.change)}"
- .change="${change}"
- .href="${GerritNav.getUrlForChangeById(
- change._number,
- change.project
- )}"
- .showSubmittableCheck=${true}
- >${change.project}: ${change.branch}:
- ${change.subject}</gr-related-change
- >`
+ html`${this.renderMarkers(
+ submittedTogetherMarkersPredicate(index)
+ )}<gr-related-change
+ class="${classMap({
+ ['show-when-collapsed']: submittedTogetherMarkersPredicate(
+ index
+ ).showWhenCollapsed,
+ })}"
+ .change="${change}"
+ .href="${GerritNav.getUrlForChangeById(
+ change._number,
+ change.project
+ )}"
+ .showSubmittableCheck=${true}
+ >${change.project}: ${change.branch}:
+ ${change.subject}</gr-related-change
+ >`
)}
</gr-related-collapse>
<div class="note" ?hidden=${!countNonVisibleChanges}>
@@ -174,90 +232,117 @@
</div>
</section>`;
- showWhenCollapsedPredicate = this.showWhenCollapsedPredicateFactory(
+ const sameTopicMarkersPredicate = this.markersPredicateFactory(
this.sameTopicChanges.length,
- -1
+ -1,
+ sectionSize(Section.SAME_TOPIC)
);
+ isFirstNonEmpty =
+ !firstNonEmptySectionFound && !!this.sameTopicChanges?.length;
+ firstNonEmptySectionFound = firstNonEmptySectionFound || isFirstNonEmpty;
const sameTopicSection = html`<section
id="sameTopic"
?hidden=${!this.sameTopicChanges?.length}
>
<gr-related-collapse
title="Same topic"
+ class="${classMap({first: isFirstNonEmpty})}"
.length=${this.sameTopicChanges.length}
+ .numChangesWhenCollapsed=${sectionSize(Section.SAME_TOPIC)}
>
${this.sameTopicChanges.map(
(change, index) =>
- html`<gr-related-change
- class="${classMap({
- ['show-when-collapsed']: showWhenCollapsedPredicate(index),
- })}"
- .change="${change}"
- .href="${GerritNav.getUrlForChangeById(
- change._number,
- change.project
- )}"
- >${change.project}: ${change.branch}:
- ${change.subject}</gr-related-change
- >`
+ html`${this.renderMarkers(
+ sameTopicMarkersPredicate(index)
+ )}<gr-related-change
+ class="${classMap({
+ ['show-when-collapsed']: sameTopicMarkersPredicate(index)
+ .showWhenCollapsed,
+ })}"
+ .change="${change}"
+ .href="${GerritNav.getUrlForChangeById(
+ change._number,
+ change.project
+ )}"
+ >${change.project}: ${change.branch}:
+ ${change.subject}</gr-related-change
+ >`
)}
</gr-related-collapse>
</section>`;
- showWhenCollapsedPredicate = this.showWhenCollapsedPredicateFactory(
+ const mergeConflictsMarkersPredicate = this.markersPredicateFactory(
this.conflictingChanges.length,
- -1
+ -1,
+ sectionSize(Section.MERGE_CONFLICTS)
);
+ isFirstNonEmpty =
+ !firstNonEmptySectionFound && !!this.conflictingChanges?.length;
+ firstNonEmptySectionFound = firstNonEmptySectionFound || isFirstNonEmpty;
const mergeConflictsSection = html`<section
id="mergeConflicts"
?hidden=${!this.conflictingChanges?.length}
>
<gr-related-collapse
title="Merge conflicts"
+ class="${classMap({first: isFirstNonEmpty})}"
.length=${this.conflictingChanges.length}
+ .numChangesWhenCollapsed=${sectionSize(Section.MERGE_CONFLICTS)}
>
${this.conflictingChanges.map(
(change, index) =>
- html`<gr-related-change
- class="${classMap({
- ['show-when-collapsed']: showWhenCollapsedPredicate(index),
- })}"
- .change="${change}"
- .href="${GerritNav.getUrlForChangeById(
- change._number,
- change.project
- )}"
- >${change.subject}</gr-related-change
- >`
+ html`${this.renderMarkers(
+ mergeConflictsMarkersPredicate(index)
+ )}<gr-related-change
+ class="${classMap({
+ ['show-when-collapsed']: mergeConflictsMarkersPredicate(index)
+ .showWhenCollapsed,
+ })}"
+ .change="${change}"
+ .href="${GerritNav.getUrlForChangeById(
+ change._number,
+ change.project
+ )}"
+ >${change.subject}</gr-related-change
+ >`
)}
</gr-related-collapse>
</section>`;
- showWhenCollapsedPredicate = this.showWhenCollapsedPredicateFactory(
+ const cherryPicksMarkersPredicate = this.markersPredicateFactory(
this.cherryPickChanges.length,
- -1
+ -1,
+ sectionSize(Section.CHERRY_PICKS)
);
+ isFirstNonEmpty =
+ !firstNonEmptySectionFound && !!this.cherryPickChanges?.length;
+ firstNonEmptySectionFound = firstNonEmptySectionFound || isFirstNonEmpty;
const cherryPicksSection = html`<section
id="cherryPicks"
?hidden=${!this.cherryPickChanges?.length}
>
<gr-related-collapse
title="Cherry picks"
+ class="${classMap({first: isFirstNonEmpty})}"
.length=${this.cherryPickChanges.length}
+ .numChangesWhenCollapsed=${sectionSize(Section.CHERRY_PICKS)}
>
${this.cherryPickChanges.map(
(change, index) =>
- html`<gr-related-change
- class="${classMap({
- ['show-when-collapsed']: showWhenCollapsedPredicate(index),
- })}"
- .change="${change}"
- .href="${GerritNav.getUrlForChangeById(
- change._number,
- change.project
- )}"
- >${change.branch}: ${change.subject}</gr-related-change
- >`
+ html`${this.renderMarkers(
+ cherryPicksMarkersPredicate(index)
+ )}<gr-related-change
+ class="${classMap({
+ ['show-when-collapsed']: cherryPicksMarkersPredicate(index)
+ .showWhenCollapsed,
+ })}"
+ .change="${change}"
+ .href="${GerritNav.getUrlForChangeById(
+ change._number,
+ change.project
+ )}"
+ >${change.branch}: ${change.subject}</gr-related-change
+ >`
)}
</gr-related-collapse>
</section>`;
@@ -271,17 +356,140 @@
</gr-endpoint-decorator>`;
}
- showWhenCollapsedPredicateFactory(length: number, highlightIndex: number) {
- return (index: number) => {
- if (highlightIndex === -1) return index < MAX_CHANGES_WHEN_COLLAPSED;
- if (highlightIndex === 0) return index <= MAX_CHANGES_WHEN_COLLAPSED - 1;
+ sectionSizeFactory(
+ relatedChangesLen: number,
+ submittedTogetherLen: number,
+ sameTopicLen: number,
+ mergeConflictsLen: number,
+ cherryPicksLen: number
+ ) {
+ const calcDefaultSize = (length: number) =>
+ Math.min(length, DEFALT_NUM_CHANGES_WHEN_COLLAPSED);
+
+ const sectionSizes = [
+ {
+ section: Section.RELATED_CHANGES,
+ size: calcDefaultSize(relatedChangesLen),
+ len: relatedChangesLen,
+ },
+ {
+ section: Section.SUBMITTED_TOGETHER,
+ size: calcDefaultSize(submittedTogetherLen),
+ len: submittedTogetherLen,
+ },
+ {
+ section: Section.SAME_TOPIC,
+ size: calcDefaultSize(sameTopicLen),
+ len: sameTopicLen,
+ },
+ {
+ section: Section.MERGE_CONFLICTS,
+ size: calcDefaultSize(mergeConflictsLen),
+ len: mergeConflictsLen,
+ },
+ {
+ section: Section.CHERRY_PICKS,
+ size: calcDefaultSize(cherryPicksLen),
+ len: cherryPicksLen,
+ },
+ ];
+
+ const FILLER = 1; // space for header
+ let totalSize = sectionSizes.reduce(
+ (acc, val) => acc + val.size + (val.size !== 0 ? FILLER : 0),
+ 0
+ );
+
+ const MAX_SIZE = 16;
+ for (let i = 0; i < sectionSizes.length; i++) {
+ if (totalSize >= MAX_SIZE) break;
+ const sizeObj = sectionSizes[i];
+ if (sizeObj.size === sizeObj.len) continue;
+ const newSize = Math.min(
+ MAX_SIZE - totalSize + sizeObj.size,
+ sizeObj.len
+ );
+ totalSize += newSize - sizeObj.size;
+ sizeObj.size = newSize;
+ }
+
+ return (section: Section) => {
+ const sizeObj = sectionSizes.find(sizeObj => sizeObj.section === section);
+ if (sizeObj) return sizeObj.size;
+ return DEFALT_NUM_CHANGES_WHEN_COLLAPSED;
+ };
+ }
+
+ markersPredicateFactory(
+ length: number,
+ highlightIndex: number,
+ numChangesShownWhenCollapsed = DEFALT_NUM_CHANGES_WHEN_COLLAPSED
+ ): (index: number) => ChangeMarkersInList {
+ const showWhenCollapsedPredicate = (index: number) => {
+ if (highlightIndex === -1) return index < numChangesShownWhenCollapsed;
+ if (highlightIndex === 0)
+ return index <= numChangesShownWhenCollapsed - 1;
if (highlightIndex === length - 1)
- return index >= length - MAX_CHANGES_WHEN_COLLAPSED;
+ return index >= length - numChangesShownWhenCollapsed;
+ let numBeforeHighlight = Math.floor(numChangesShownWhenCollapsed / 2);
+ let numAfterHighlight =
+ Math.floor(numChangesShownWhenCollapsed / 2) -
+ (numChangesShownWhenCollapsed % 2 ? 0 : 1);
+ numBeforeHighlight += Math.max(
+ highlightIndex + numAfterHighlight - length + 1,
+ 0
+ );
+ numAfterHighlight -= Math.min(0, highlightIndex - numBeforeHighlight);
return (
- highlightIndex - MAX_CHANGES_WHEN_COLLAPSED + 2 <= index &&
- index <= highlightIndex + MAX_CHANGES_WHEN_COLLAPSED - 2
+ highlightIndex - numBeforeHighlight <= index &&
+ index <= highlightIndex + numAfterHighlight
);
};
+ return (index: number) => {
+ return {
+ showCurrentChangeArrow:
+ highlightIndex !== -1 && index === highlightIndex,
+ showWhenCollapsed: showWhenCollapsedPredicate(index),
+ showTopArrow:
+ index >= 1 &&
+ index !== highlightIndex &&
+ showWhenCollapsedPredicate(index) &&
+ !showWhenCollapsedPredicate(index - 1),
+ showBottomArrow:
+ index <= length - 2 &&
+ index !== highlightIndex &&
+ showWhenCollapsedPredicate(index) &&
+ !showWhenCollapsedPredicate(index + 1),
+ };
+ };
+ }
+
+ renderMarkers(changeMarkers: ChangeMarkersInList) {
+ if (changeMarkers.showCurrentChangeArrow) {
+ return html`<span
+ role="img"
+ class="arrowToCurrentChange"
+ aria-label="Arrow marking current change"
+ >âž”</span
+ >`;
+ }
+ if (changeMarkers.showTopArrow) {
+ return html`<span
+ role="img"
+ class="marker"
+ aria-label="Arrow marking change has collapsed ancestors"
+ ><iron-icon icon="gr-icons:arrowDropUp"></iron-icon
+ ></span> `;
+ }
+ if (changeMarkers.showBottomArrow) {
+ return html`<span
+ role="img"
+ class="marker"
+ aria-label="Arrow marking change has collapsed descendants"
+ ><iron-icon icon="gr-icons:arrowDropDown"></iron-icon
+ ></span> `;
+ }
+ return nothing;
}
reload(getRelatedChanges?: Promise<RelatedChangesInfo | undefined>) {
@@ -429,6 +637,9 @@
@property()
length = 0;
+ @property()
+ numChangesWhenCollapsed = DEFALT_NUM_CHANGES_WHEN_COLLAPSED;
+
private readonly reporting = appContext.reportingService;
static get styles() {
@@ -458,13 +669,25 @@
width: 1.2em;
}
.collapsed ::slotted(gr-related-change.show-when-collapsed) {
- display: flex;
+ visibility: visible;
+ height: auto;
}
- .collapsed ::slotted(gr-related-change) {
+ .collapsed ::slotted(.marker) {
+ display: block;
+ }
+ .show-all ::slotted(.marker) {
display: none;
}
+ /* keep width, so width of section and position of show all button
+ * are set according to width of all (even hidden) elements
+ */
+ .collapsed ::slotted(gr-related-change) {
+ visibility: hidden;
+ height: 0px;
+ }
::slotted(gr-related-change) {
- display: flex;
+ visibility: visible;
+ height: auto;
}
gr-button iron-icon {
color: inherit;
@@ -476,6 +699,9 @@
display: flex;
margin-bottom: var(--spacing-s);
}
+ :host(.first) .container {
+ margin-bottom: var(--spacing-m);
+ }
`,
];
}
@@ -483,25 +709,24 @@
render() {
const title = html`<h4 class="title">${this.title}</h4>`;
- const collapsible = this.length > MAX_CHANGES_WHEN_COLLAPSED;
+ const collapsible = this.length > this.numChangesWhenCollapsed;
const items = html` <div
- class="${!this.showAll && collapsible ? 'collapsed' : ''}"
+ class="${!this.showAll && collapsible ? 'collapsed' : 'show-all'}"
>
<slot></slot>
</div>`;
- let button = nothing;
+ let button: TemplateResult | typeof nothing = nothing;
if (collapsible) {
- if (this.showAll) {
- button = html`<gr-button link="" @click="${this.toggle}"
- >Show less<iron-icon icon="gr-icons:expand-less"></iron-icon
- ></gr-button>`;
- } else {
- button = html`<gr-button link="" @click="${this.toggle}"
- >Show all (${this.length})
- <iron-icon icon="gr-icons:expand-more"></iron-icon
- ></gr-button>`;
+ let buttonText = 'Show less';
+ let buttonIcon = 'expand-less';
+ if (!this.showAll) {
+ buttonText = `Show all (${this.length})`;
+ buttonIcon = 'expand-more';
}
+ button = html`<gr-button link="" @click="${this.toggle}"
+ >${buttonText}<iron-icon icon="gr-icons:${buttonIcon}"></iron-icon
+ ></gr-button>`;
}
return html`<div class="container">${title}${button}</div>
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental_test.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental_test.ts
new file mode 100644
index 0000000..5769284
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list-experimental/gr-related-changes-list-experimental_test.ts
@@ -0,0 +1,249 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import {
+ createChange,
+ createParsedChange,
+ createRelatedChangeAndCommitInfo,
+ createRelatedChangesInfo,
+ createSubmittedTogetherInfo,
+} from '../../../test/test-data-generators';
+import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {
+ PatchSetNum,
+ RelatedChangesInfo,
+ SubmittedTogetherInfo,
+} from '../../../types/common';
+import './gr-related-changes-list-experimental';
+import {
+ ChangeMarkersInList,
+ GrRelatedChangesListExperimental,
+ GrRelatedCollapse,
+ Section,
+} from './gr-related-changes-list-experimental';
+
+const basicFixture = fixtureFromElement('gr-related-changes-list-experimental');
+
+suite('gr-related-changes-list-experimental', () => {
+ let element: GrRelatedChangesListExperimental;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+
+ suite('show when collapsed', () => {
+ function genBoolArray(
+ instructions: Array<{
+ len: number;
+ v: boolean;
+ }>
+ ) {
+ return instructions
+ .map(inst => Array.from({length: inst.len}, () => inst.v))
+ .reduce((acc, val) => acc.concat(val), []);
+ }
+
+ function checkShowWhenCollapsed(
+ expected: boolean[],
+ markersPredicate: (index: number) => ChangeMarkersInList,
+ msg: string
+ ) {
+ for (let i = 0; i < expected.length; i++) {
+ assert.equal(
+ markersPredicate(i).showWhenCollapsed,
+ expected[i],
+ `change on pos (${i}) ${msg}`
+ );
+ }
+ }
+
+ test('size 5', () => {
+ const markersPredicate = element.markersPredicateFactory(10, 4, 5);
+ const expectedCollapsing = genBoolArray([
+ {len: 2, v: false},
+ {len: 5, v: true},
+ {len: 3, v: false},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing,
+ markersPredicate,
+ 'highlight 4, size 10, size 5'
+ );
+
+ const markersPredicate2 = element.markersPredicateFactory(10, 8, 5);
+ const expectedCollapsing2 = genBoolArray([
+ {len: 5, v: false},
+ {len: 5, v: true},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing2,
+ markersPredicate2,
+ 'highlight 8, size 10, size 5'
+ );
+
+ const markersPredicate3 = element.markersPredicateFactory(10, 1, 5);
+ const expectedCollapsing3 = genBoolArray([
+ {len: 5, v: true},
+ {len: 5, v: false},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing3,
+ markersPredicate3,
+ 'highlight 1, size 10, size 5'
+ );
+ });
+
+ test('size 4', () => {
+ const markersPredicate = element.markersPredicateFactory(10, 4, 4);
+ const expectedCollapsing = genBoolArray([
+ {len: 2, v: false},
+ {len: 4, v: true},
+ {len: 4, v: false},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing,
+ markersPredicate,
+ 'highlight 4, len 10, size 4'
+ );
+
+ const markersPredicate2 = element.markersPredicateFactory(10, 8, 4);
+ const expectedCollapsing2 = genBoolArray([
+ {len: 6, v: false},
+ {len: 4, v: true},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing2,
+ markersPredicate2,
+ 'highlight 8, len 10, size 4'
+ );
+
+ const markersPredicate3 = element.markersPredicateFactory(10, 1, 4);
+ const expectedCollapsing3 = genBoolArray([
+ {len: 4, v: true},
+ {len: 6, v: false},
+ ]);
+ checkShowWhenCollapsed(
+ expectedCollapsing3,
+ markersPredicate3,
+ 'highlight 1, len 10, size 4'
+ );
+ });
+ });
+
+ suite('section size', () => {
+ test('1 section', () => {
+ const sectionSize = element.sectionSizeFactory(20, 0, 0, 0, 0);
+ assert.equal(sectionSize(Section.RELATED_CHANGES), 15);
+ const sectionSize2 = element.sectionSizeFactory(0, 0, 10, 0, 0);
+ assert.equal(sectionSize2(Section.SAME_TOPIC), 10);
+ });
+ test('2 sections', () => {
+ const sectionSize = element.sectionSizeFactory(20, 20, 0, 0, 0);
+ assert.equal(sectionSize(Section.RELATED_CHANGES), 11);
+ assert.equal(sectionSize(Section.SUBMITTED_TOGETHER), 3);
+ const sectionSize2 = element.sectionSizeFactory(4, 0, 10, 0, 0);
+ assert.equal(sectionSize2(Section.RELATED_CHANGES), 4);
+ assert.equal(sectionSize2(Section.SAME_TOPIC), 10);
+ });
+ test('many sections', () => {
+ const sectionSize = element.sectionSizeFactory(20, 20, 3, 3, 3);
+ assert.equal(sectionSize(Section.RELATED_CHANGES), 3);
+ assert.equal(sectionSize(Section.SUBMITTED_TOGETHER), 3);
+ const sectionSize2 = element.sectionSizeFactory(4, 1, 10, 1, 1);
+ assert.equal(sectionSize2(Section.RELATED_CHANGES), 4);
+ assert.equal(sectionSize2(Section.SAME_TOPIC), 4);
+ });
+ });
+
+ suite('test first non-empty list', () => {
+ const relatedChangeInfo: RelatedChangesInfo = {
+ ...createRelatedChangesInfo(),
+ changes: [createRelatedChangeAndCommitInfo()],
+ };
+ const submittedTogether: SubmittedTogetherInfo = {
+ ...createSubmittedTogetherInfo(),
+ changes: [createChange()],
+ };
+
+ setup(() => {
+ element.change = createParsedChange();
+ element.patchNum = 1 as PatchSetNum;
+ });
+
+ test('first list', async () => {
+ stubRestApi('getRelatedChanges').returns(
+ Promise.resolve(relatedChangeInfo)
+ );
+ await element.reload();
+ const section = queryAndAssert<HTMLElement>(element, '#relatedChanges');
+ const relatedChanges = queryAndAssert<GrRelatedCollapse>(
+ section,
+ 'gr-related-collapse'
+ );
+ assert.isTrue(relatedChanges!.classList.contains('first'));
+ });
+
+ test('first empty second non-empty', async () => {
+ stubRestApi('getRelatedChanges').returns(
+ Promise.resolve(createRelatedChangesInfo())
+ );
+ stubRestApi('getChangesSubmittedTogether').returns(
+ Promise.resolve(submittedTogether)
+ );
+ await element.reload();
+ const relatedChanges = queryAndAssert<GrRelatedCollapse>(
+ queryAndAssert<HTMLElement>(element, '#relatedChanges'),
+ 'gr-related-collapse'
+ );
+ assert.isFalse(relatedChanges!.classList.contains('first'));
+ const submittedTogetherSection = queryAndAssert<GrRelatedCollapse>(
+ queryAndAssert<HTMLElement>(element, '#submittedTogether'),
+ 'gr-related-collapse'
+ );
+ assert.isTrue(submittedTogetherSection!.classList.contains('first'));
+ });
+
+ test('first non-empty second empty third non-empty', async () => {
+ stubRestApi('getRelatedChanges').returns(
+ Promise.resolve(relatedChangeInfo)
+ );
+ stubRestApi('getChangesSubmittedTogether').returns(
+ Promise.resolve(createSubmittedTogetherInfo())
+ );
+ stubRestApi('getChangeCherryPicks').returns(
+ Promise.resolve([createChange()])
+ );
+ await element.reload();
+ const relatedChanges = queryAndAssert<GrRelatedCollapse>(
+ queryAndAssert<HTMLElement>(element, '#relatedChanges'),
+ 'gr-related-collapse'
+ );
+ assert.isTrue(relatedChanges!.classList.contains('first'));
+ const submittedTogetherSection = queryAndAssert<GrRelatedCollapse>(
+ queryAndAssert<HTMLElement>(element, '#submittedTogether'),
+ 'gr-related-collapse'
+ );
+ assert.isFalse(submittedTogetherSection!.classList.contains('first'));
+ const cherryPicks = queryAndAssert<GrRelatedCollapse>(
+ queryAndAssert<HTMLElement>(element, '#cherryPicks'),
+ 'gr-related-collapse'
+ );
+ assert.isFalse(cherryPicks!.classList.contains('first'));
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
index 5705c4f..927f3c9 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
@@ -19,8 +19,6 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../plugins/gr-endpoint-slot/gr-endpoint-slot';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-related-changes-list_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -53,9 +51,7 @@
}
@customElement('gr-related-changes-list')
-export class GrRelatedChangesList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRelatedChangesList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -303,8 +299,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
// We listen to `new-section-loaded` events to allow plugins to trigger
// visibility computations, if their content or visibility changed.
this.addEventListener('new-section-loaded', () =>
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js
deleted file mode 100644
index f54b819..0000000
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js
+++ /dev/null
@@ -1,631 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-related-changes-list.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {resetPlugins} from '../../../test/test-utils.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-const basicFixture = fixtureFromElement('gr-related-changes-list');
-
-suite('gr-related-changes-list tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('connected revisions', () => {
- const change = {
- revisions: {
- 'e3c6d60783bfdec9ebae7dcfec4662360433449e': {
- _number: 1,
- },
- '26e5e4c9c7ae31cbd876271cca281ce22b413997': {
- _number: 2,
- },
- 'bf7884d695296ca0c91702ba3e2bc8df0f69a907': {
- _number: 7,
- },
- 'b5fc49f2e67d1889d5275cac04ad3648f2ec7fe3': {
- _number: 5,
- },
- 'd6bcee67570859ccb684873a85cf50b1f0e96fda': {
- _number: 6,
- },
- 'cc960918a7f90388f4a9e05753d0f7b90ad44546': {
- _number: 3,
- },
- '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6': {
- _number: 4,
- },
- },
- };
- let patchNum = 7;
- let relatedChanges = [
- {
- commit: {
- commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
- parents: [
- {
- commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
- },
- ],
- },
- },
- {
- commit: {
- commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
- parents: [
- {
- commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
- },
- ],
- },
- },
- {
- commit: {
- commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
- parents: [
- {
- commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
- },
- ],
- },
- },
- {
- commit: {
- commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
- parents: [
- {
- commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
- },
- ],
- },
- },
- {
- commit: {
- commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
- parents: [
- {
- commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce',
- },
- ],
- },
- },
- {
- commit: {
- commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce',
- parents: [
- {
- commit: '455ed9cd27a16bf6991f04dcc57ef575dc4d5e75',
- },
- ],
- },
- },
- ];
-
- let connectedChanges =
- element._computeConnectedRevisions(change, patchNum, relatedChanges);
- assert.deepEqual(connectedChanges, [
- '613bc4f81741a559c6667ac08d71dcc3348f73ce',
- 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
- 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
- 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
- '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
- '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
- '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
- ]);
-
- patchNum = 4;
- relatedChanges = [
- {
- commit: {
- commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
- parents: [
- {
- commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
- },
- ],
- },
- },
- {
- commit: {
- commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
- parents: [
- {
- commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
- },
- ],
- },
- },
- {
- commit: {
- commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
- parents: [
- {
- commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
- },
- ],
- },
- },
- {
- commit: {
- commit: 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b',
- parents: [
- {
- commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
- },
- ],
- },
- },
- {
- commit: {
- commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
- parents: [
- {
- commit: 'af815dac54318826b7f1fa468acc76349ffc588e',
- },
- ],
- },
- },
- {
- commit: {
- commit: 'af815dac54318826b7f1fa468acc76349ffc588e',
- parents: [
- {
- commit: '58f76e406e24cb8b0f5d64c7f5ac1e8616d0a22c',
- },
- ],
- },
- },
- ];
-
- connectedChanges =
- element._computeConnectedRevisions(change, patchNum, relatedChanges);
- assert.deepEqual(connectedChanges, [
- 'af815dac54318826b7f1fa468acc76349ffc588e',
- '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
- '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
- 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b',
- ]);
- });
-
- test('_changesEqual', () => {
- const change1 = {change_id: 123, _number: 0};
- const change2 = {change_id: 456, _number: 1};
- const change3 = {change_id: 123, _number: 2};
- const change4 = {change_id: 123, _change_number: 1};
-
- assert.isTrue(element._changesEqual(change1, change1));
- assert.isFalse(element._changesEqual(change1, change2));
- assert.isFalse(element._changesEqual(change1, change3));
- assert.isTrue(element._changesEqual(change2, change4));
- });
-
- test('_getChangeNumber', () => {
- const change1 = {change_id: 123, _number: 0};
- const change2 = {change_id: 456, _change_number: 1};
- assert.equal(element._getChangeNumber(change1), 0);
- assert.equal(element._getChangeNumber(change2), 1);
- });
-
- test('event for section loaded fires for each section ', () => {
- const loadedStub = sinon.stub();
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'NEW',
- };
- element.mergeable = true;
- element.addEventListener('new-section-loaded', loadedStub);
- stubRestApi('getRelatedChanges').returns(Promise.resolve({changes: []}));
- stubRestApi('getChangesSubmittedTogether').returns(Promise.resolve());
- stubRestApi('getChangeCherryPicks').returns(Promise.resolve());
- stubRestApi('getChangeConflicts').returns(Promise.resolve());
-
- return element.reload().then(() => {
- assert.equal(loadedStub.callCount, 4);
- });
- });
-
- suite('getChangeConflicts resolves undefined', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
-
- stubRestApi('getRelatedChanges').returns(Promise.resolve({changes: []}));
- stubRestApi('getChangesSubmittedTogether').returns(Promise.resolve());
- stubRestApi('getChangeCherryPicks').returns(Promise.resolve());
- stubRestApi('getChangeConflicts').returns(Promise.resolve());
- });
-
- test('_conflicts are an empty array', () => {
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'NEW',
- };
- element.mergeable = true;
- element.reload();
- assert.equal(element._conflicts.length, 0);
- });
- });
-
- suite('get conflicts tests', () => {
- let element;
- let conflictsStub;
-
- setup(() => {
- element = basicFixture.instantiate();
-
- stubRestApi('getRelatedChanges').returns(Promise.resolve({changes: []}));
- stubRestApi('getChangesSubmittedTogether').returns(Promise.resolve());
- stubRestApi('getChangeCherryPicks').returns(Promise.resolve());
- conflictsStub = stubRestApi('getChangeConflicts').returns(
- Promise.resolve());
- });
-
- test('request conflicts if open and mergeable', () => {
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'NEW',
- };
- element.mergeable = true;
- element.reload();
- assert.isTrue(conflictsStub.called);
- });
-
- test('does not request conflicts if closed and mergeable', () => {
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'MERGED',
- };
- element.reload();
- assert.isFalse(conflictsStub.called);
- });
-
- test('does not request conflicts if open and not mergeable', () => {
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'NEW',
- };
- element.mergeable = false;
- element.reload();
- assert.isFalse(conflictsStub.called);
- });
-
- test('doesnt request conflicts if closed and not mergeable', () => {
- element.patchNum = 7;
- element.change = {
- change_id: 123,
- status: 'MERGED',
- };
- element.mergeable = false;
- element.reload();
- assert.isFalse(conflictsStub.called);
- });
- });
-
- test('_calculateHasParent', () => {
- const changeId = 123;
- const relatedChanges = [];
-
- assert.equal(element._calculateHasParent(changeId, relatedChanges),
- false);
-
- relatedChanges.push({change_id: 123});
- assert.equal(element._calculateHasParent(changeId, relatedChanges),
- false);
-
- relatedChanges.push({change_id: 234});
- assert.equal(element._calculateHasParent(changeId, relatedChanges),
- true);
- });
-
- suite('hidden attribute and update event', () => {
- const changes = [{
- project: 'foo/bar',
- change_id: 'Ideadbeef',
- commit: {
- commit: 'deadbeef',
- parents: [{commit: 'abc123'}],
- author: {},
- subject: 'do that thing',
- },
- _change_number: 12345,
- _revision_number: 1,
- _current_revision_number: 1,
- status: 'NEW',
- }];
-
- test('clear and empties', () => {
- element._relatedResponse = {changes};
- element._submittedTogether = {changes};
- element._conflicts = changes;
- element._cherryPicks = changes;
- element._sameTopic = changes;
-
- element.hidden = false;
- element.clear();
- assert.isTrue(element.hidden);
- assert.equal(element._relatedResponse.changes.length, 0);
- assert.equal(element._submittedTogether.changes.length, 0);
- assert.equal(element._conflicts.length, 0);
- assert.equal(element._cherryPicks.length, 0);
- assert.equal(element._sameTopic.length, 0);
- });
-
- test('update fires', () => {
- const updateHandler = sinon.stub();
- element.addEventListener('update', updateHandler);
-
- element._resultsChanged({}, {}, [], [], []);
- assert.isTrue(element.hidden);
- assert.isFalse(updateHandler.called);
-
- element._resultsChanged({}, {}, [], [], ['test']);
- assert.isFalse(element.hidden);
- assert.isTrue(updateHandler.called);
- updateHandler.reset();
-
- element._resultsChanged(
- {}, {changes: [], non_visible_changes: 0}, [], [], []);
- assert.isTrue(element.hidden);
- assert.isFalse(updateHandler.called);
-
- element._resultsChanged(
- {}, {changes: ['test'], non_visible_changes: 0}, [], [], []);
- assert.isFalse(element.hidden);
- assert.isTrue(updateHandler.called);
- updateHandler.reset();
-
- element._resultsChanged(
- {}, {changes: [], non_visible_changes: 1}, [], [], []);
- assert.isFalse(element.hidden);
- assert.isTrue(updateHandler.called);
- });
-
- suite('hiding and unhiding', () => {
- test('related response', () => {
- assert.isTrue(element.hidden);
- element._resultsChanged({changes}, {}, [], [], []);
- assert.isFalse(element.hidden);
- });
-
- test('submitted together', () => {
- assert.isTrue(element.hidden);
- element._resultsChanged({}, {changes}, [], [], []);
- assert.isFalse(element.hidden);
- });
-
- test('conflicts', () => {
- assert.isTrue(element.hidden);
- element._resultsChanged({}, {}, changes, [], []);
- assert.isFalse(element.hidden);
- });
-
- test('cherrypicks', () => {
- assert.isTrue(element.hidden);
- element._resultsChanged({}, {}, [], changes, []);
- assert.isFalse(element.hidden);
- });
-
- test('same topic', () => {
- assert.isTrue(element.hidden);
- element._resultsChanged({}, {}, [], [], changes);
- assert.isFalse(element.hidden);
- });
- });
- });
-
- test('_computeChangeURL uses GerritNav', () => {
- const getUrlStub = sinon.stub(GerritNav, 'getUrlForChangeById');
- element._computeChangeURL(123, 'abc/def', 12);
- assert.isTrue(getUrlStub.called);
- });
-
- suite('submitted together changes', () => {
- const change = {
- project: 'foo/bar',
- change_id: 'Ideadbeef',
- commit: {
- commit: 'deadbeef',
- parents: [{commit: 'abc123'}],
- author: {},
- subject: 'do that thing',
- },
- _change_number: 12345,
- _revision_number: 1,
- _current_revision_number: 1,
- status: 'NEW',
- };
-
- test('_computeSubmittedTogetherClass', () => {
- assert.strictEqual(
- element._computeSubmittedTogetherClass(undefined),
- 'hidden');
- assert.strictEqual(
- element._computeSubmittedTogetherClass({changes: []}),
- 'hidden');
- assert.strictEqual(
- element._computeSubmittedTogetherClass({changes: [{}]}),
- '');
- assert.strictEqual(
- element._computeSubmittedTogetherClass({
- changes: [],
- non_visible_changes: 0,
- }),
- 'hidden');
- assert.strictEqual(
- element._computeSubmittedTogetherClass({
- changes: [],
- non_visible_changes: 1,
- }),
- '');
- assert.strictEqual(
- element._computeSubmittedTogetherClass({
- changes: [{}],
- non_visible_changes: 1,
- }),
- '');
- });
-
- test('no submitted together changes', () => {
- flush();
- assert.include(element.$.submittedTogether.className, 'hidden');
- });
-
- test('no non-visible submitted together changes', () => {
- element._submittedTogether = {changes: [change]};
- flush();
- assert.notInclude(element.$.submittedTogether.className, 'hidden');
- assert.isNull(element.shadowRoot
- .querySelector('.note'));
- });
-
- test('no visible submitted together changes', () => {
- // Technically this should never happen, but worth asserting the logic.
- element._submittedTogether = {changes: [], non_visible_changes: 1};
- flush();
- assert.notInclude(element.$.submittedTogether.className, 'hidden');
- assert.isNotNull(element.shadowRoot
- .querySelector('.note'));
- assert.strictEqual(
- element.shadowRoot
- .querySelector('.note').innerText.trim(),
- '(+ 1 non-visible change)');
- });
-
- test('visible and non-visible submitted together changes', () => {
- element._submittedTogether = {changes: [change], non_visible_changes: 2};
- flush();
- assert.notInclude(element.$.submittedTogether.className, 'hidden');
- assert.isNotNull(element.shadowRoot
- .querySelector('.note'));
- assert.strictEqual(
- element.shadowRoot
- .querySelector('.note').innerText.trim(),
- '(+ 2 non-visible changes)');
- });
- });
-});
-
-suite('gr-related-changes-list plugin tests', () => {
- let element;
-
- setup(() => {
- resetPlugins();
- element = basicFixture.instantiate();
- });
-
- teardown(() => {
- resetPlugins();
- });
-
- test('endpoint params', done => {
- element.change = {labels: {}};
- let hookEl;
- let plugin;
- pluginApi.install(
- p => {
- plugin = p;
- plugin.hook('related-changes-section').getLastAttached()
- .then(el => hookEl = el);
- },
- '0.1',
- 'http://some/plugins/url1.html');
- getPluginLoader().loadPlugins([]);
- flush(() => {
- assert.strictEqual(hookEl.plugin, plugin);
- assert.strictEqual(hookEl.change, element.change);
- done();
- });
- });
-
- test('hiding and unhiding', done => {
- element.change = {labels: {}};
- let hookEl;
- let plugin;
-
- // No changes, and no plugin. The element is still hidden.
- element._resultsChanged({}, {}, [], [], []);
- assert.isTrue(element.hidden);
- pluginApi.install(
- p => {
- plugin = p;
- plugin.hook('related-changes-section').getLastAttached()
- .then(el => hookEl = el);
- },
- '0.1',
- 'http://some/plugins/url2.html');
- getPluginLoader().loadPlugins([]);
- flush(() => {
- // No changes, and plugin without hidden attribute. So it's visible.
- element._resultsChanged({}, {}, [], [], []);
- assert.isFalse(element.hidden);
-
- // No changes, but plugin with true hidden attribute. So it's invisible.
- hookEl.hidden = true;
-
- element._resultsChanged({}, {}, [], [], []);
- assert.isTrue(element.hidden);
-
- // No changes, and plugin with false hidden attribute. So it's visible.
- hookEl.hidden = false;
- element._resultsChanged({}, {}, [], [], []);
- assert.isFalse(element.hidden);
-
- // Hiding triggered by plugin itself
- hookEl.hidden = true;
- hookEl.dispatchEvent(new CustomEvent('new-section-loaded', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(element.hidden);
-
- // Unhiding triggered by plugin itself
- hookEl.hidden = false;
- hookEl.dispatchEvent(new CustomEvent('new-section-loaded', {
- composed: true, bubbles: true,
- }));
- assert.isFalse(element.hidden);
-
- // Hiding plugin keeps list visible, if there are changes
- hookEl.hidden = false;
- element._sameTopic = ['test'];
- element._resultsChanged({}, {}, [], [], ['test']);
- assert.isFalse(element.hidden);
- hookEl.hidden = true;
- hookEl.dispatchEvent(new CustomEvent('new-section-loaded', {
- composed: true, bubbles: true,
- }));
- assert.isFalse(element.hidden);
-
- done();
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
new file mode 100644
index 0000000..c4bfe77
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
@@ -0,0 +1,853 @@
+/**
+ * @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.
+ */
+
+import {ChangeStatus} from '../../../constants/constants';
+import '../../../test/common-test-setup-karma';
+import {
+ createChange,
+ createCommit,
+ createCommitInfoWithRequiredCommit,
+ createParsedChange,
+ createRelatedChangeAndCommitInfo,
+ createRevision,
+} from '../../../test/test-data-generators';
+import {
+ ChangeId,
+ ChangeInfo,
+ CommitId,
+ NumericChangeId,
+ PatchSetNum,
+ RelatedChangeAndCommitInfo,
+ RepoName,
+} from '../../../types/common';
+import {ParsedChangeInfo} from '../../../types/types';
+import './gr-related-changes-list';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
+import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit';
+import {
+ query,
+ queryAndAssert,
+ resetPlugins,
+ stubRestApi,
+} from '../../../test/test-utils';
+import {GrRelatedChangesList} from './gr-related-changes-list';
+import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
+import {PluginApi} from '../../../api/plugin';
+import {GrEndpointDecorator} from '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import {_testOnly_resetEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
+
+const pluginApi = _testOnly_initGerritPluginApi();
+
+const basicFixture = fixtureFromElement('gr-related-changes-list');
+
+suite('gr-related-changes-list tests', () => {
+ let element: GrRelatedChangesList;
+
+ setup(() => {
+ // Since pluginEndpoints are global, must reset state.
+ _testOnly_resetEndpoints();
+ element = basicFixture.instantiate();
+ });
+
+ test('connected revisions', () => {
+ const change: ParsedChangeInfo = {
+ ...createParsedChange(),
+ revisions: {
+ e3c6d60783bfdec9ebae7dcfec4662360433449e: createRevision(1),
+ '26e5e4c9c7ae31cbd876271cca281ce22b413997': createRevision(2),
+ bf7884d695296ca0c91702ba3e2bc8df0f69a907: createRevision(7),
+ b5fc49f2e67d1889d5275cac04ad3648f2ec7fe3: createRevision(5),
+ d6bcee67570859ccb684873a85cf50b1f0e96fda: createRevision(6),
+ cc960918a7f90388f4a9e05753d0f7b90ad44546: createRevision(3),
+ '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6': createRevision(4),
+ },
+ };
+ let patchNum = 7 as PatchSetNum;
+ let relatedChanges: RelatedChangeAndCommitInfo[] = [
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '2cebeedfb1e80f4b872d0a13ade529e70652c0c8'
+ ),
+ parents: [
+ {
+ commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd' as CommitId,
+ subject: 'subject1',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '87ed20b241576b620bbaa3dfd47715ce6782b7dd'
+ ),
+ parents: [
+ {
+ commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb' as CommitId,
+ subject: 'subject2',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb'
+ ),
+ parents: [
+ {
+ commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae' as CommitId,
+ subject: 'subject3',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ 'b0ccb183494a8e340b8725a2dc553967d61e6dae'
+ ),
+ parents: [
+ {
+ commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907' as CommitId,
+ subject: 'subject4',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ 'bf7884d695296ca0c91702ba3e2bc8df0f69a907'
+ ),
+ parents: [
+ {
+ commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce' as CommitId,
+ subject: 'subject5',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '613bc4f81741a559c6667ac08d71dcc3348f73ce'
+ ),
+ parents: [
+ {
+ commit: '455ed9cd27a16bf6991f04dcc57ef575dc4d5e75' as CommitId,
+ subject: 'subject6',
+ },
+ ],
+ },
+ },
+ ];
+
+ let connectedChanges = element._computeConnectedRevisions(
+ change,
+ patchNum,
+ relatedChanges
+ );
+ assert.deepEqual(connectedChanges, [
+ '613bc4f81741a559c6667ac08d71dcc3348f73ce',
+ 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
+ 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
+ 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
+ '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
+ '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
+ '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
+ ]);
+
+ patchNum = 4 as PatchSetNum;
+ relatedChanges = [
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '2cebeedfb1e80f4b872d0a13ade529e70652c0c8'
+ ),
+ parents: [
+ {
+ commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '87ed20b241576b620bbaa3dfd47715ce6782b7dd'
+ ),
+ parents: [
+ {
+ commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb'
+ ),
+ parents: [
+ {
+ commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b'
+ ),
+ parents: [
+ {
+ commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6'
+ ),
+ parents: [
+ {
+ commit: 'af815dac54318826b7f1fa468acc76349ffc588e' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ {
+ ...createRelatedChangeAndCommitInfo(),
+ commit: {
+ ...createCommitInfoWithRequiredCommit(
+ 'af815dac54318826b7f1fa468acc76349ffc588e'
+ ),
+ parents: [
+ {
+ commit: '58f76e406e24cb8b0f5d64c7f5ac1e8616d0a22c' as CommitId,
+ subject: 'My parent commit',
+ },
+ ],
+ },
+ },
+ ];
+
+ connectedChanges = element._computeConnectedRevisions(
+ change,
+ patchNum,
+ relatedChanges
+ );
+ assert.deepEqual(connectedChanges, [
+ 'af815dac54318826b7f1fa468acc76349ffc588e',
+ '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
+ '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
+ 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b',
+ ]);
+ });
+
+ test('_changesEqual', () => {
+ const change1: ChangeInfo = {
+ ...createChange(),
+ change_id: '123' as ChangeId,
+ _number: 0 as NumericChangeId,
+ };
+ const change2: ChangeInfo = {
+ ...createChange(),
+ change_id: '456' as ChangeId,
+ _number: 1 as NumericChangeId,
+ };
+ const change3: ChangeInfo = {
+ ...createChange(),
+ change_id: '123' as ChangeId,
+ _number: 2 as NumericChangeId,
+ };
+ const change4: RelatedChangeAndCommitInfo = {
+ ...createRelatedChangeAndCommitInfo(),
+ change_id: '123' as ChangeId,
+ _change_number: 1 as NumericChangeId,
+ };
+
+ assert.isTrue(element._changesEqual(change1, change1));
+ assert.isFalse(element._changesEqual(change1, change2));
+ assert.isFalse(element._changesEqual(change1, change3));
+ assert.isTrue(element._changesEqual(change2, change4));
+ });
+
+ test('_getChangeNumber', () => {
+ const change1: ChangeInfo = {
+ ...createChange(),
+ change_id: '123' as ChangeId,
+ _number: 0 as NumericChangeId,
+ };
+ const change2: ChangeInfo = {
+ ...createChange(),
+ change_id: '456' as ChangeId,
+ _number: 1 as NumericChangeId,
+ };
+ assert.equal(element._getChangeNumber(change1), 0);
+ assert.equal(element._getChangeNumber(change2), 1);
+ });
+
+ test('event for section loaded fires for each section ', () => {
+ const loadedStub = sinon.stub();
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.mergeable = true;
+ element.addEventListener('new-section-loaded', loadedStub);
+
+ return element.reload().then(() => {
+ assert.equal(loadedStub.callCount, 4);
+ });
+ });
+
+ suite('getChangeConflicts resolves undefined', () => {
+ let element: GrRelatedChangesList;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+
+ test('_conflicts are an empty array', () => {
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.mergeable = true;
+ element.reload();
+ assert.equal(element._conflicts.length, 0);
+ });
+ });
+
+ suite('get conflicts tests', () => {
+ let element: GrRelatedChangesList;
+ let conflictsStub: SinonStubbedMember<RestApiService['getChangeConflicts']>;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ conflictsStub = stubRestApi('getChangeConflicts').returns(
+ Promise.resolve(undefined)
+ );
+ });
+
+ test('request conflicts if open and mergeable', () => {
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.mergeable = true;
+ element.reload();
+ assert.isTrue(conflictsStub.called);
+ });
+
+ test('does not request conflicts if closed and mergeable', () => {
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.reload();
+ assert.isFalse(conflictsStub.called);
+ });
+
+ test('does not request conflicts if open and not mergeable', () => {
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.mergeable = false;
+ element.reload();
+ assert.isFalse(conflictsStub.called);
+ });
+
+ test('doesnt request conflicts if closed and not mergeable', () => {
+ element.patchNum = 7 as PatchSetNum;
+ element.change = {
+ ...createParsedChange(),
+ change_id: '123' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+ element.mergeable = false;
+ element.reload();
+ assert.isFalse(conflictsStub.called);
+ });
+ });
+
+ test('_calculateHasParent', () => {
+ const changeId = '123' as ChangeId;
+ const relatedChanges: RelatedChangeAndCommitInfo[] = [];
+
+ assert.equal(element._calculateHasParent(changeId, relatedChanges), false);
+
+ relatedChanges.push({
+ ...createRelatedChangeAndCommitInfo(),
+ change_id: '123' as ChangeId,
+ });
+ assert.equal(element._calculateHasParent(changeId, relatedChanges), false);
+
+ relatedChanges.push({
+ ...createRelatedChangeAndCommitInfo(),
+ change_id: '234' as ChangeId,
+ });
+ assert.equal(element._calculateHasParent(changeId, relatedChanges), true);
+ });
+
+ suite('hidden attribute and update event', () => {
+ const changes: ChangeInfo[] = [
+ {
+ ...createChange(),
+ project: 'foo/bar' as RepoName,
+ change_id: 'Ideadbeef' as ChangeId,
+ status: ChangeStatus.NEW,
+ },
+ ];
+ const relatedChanges: RelatedChangeAndCommitInfo[] = [
+ {
+ ...createCommitInfoWithRequiredCommit(),
+ project: 'foo/bar' as RepoName,
+ change_id: 'Ideadbeef' as ChangeId,
+ commit: {
+ ...createCommit(),
+ commit: 'deadbeef' as CommitId,
+ parents: [
+ {
+ commit: 'abc123' as CommitId,
+ subject: 'abc123',
+ },
+ ],
+ subject: 'do that thing',
+ },
+ _change_number: 12345 as NumericChangeId,
+ _revision_number: 1,
+ _current_revision_number: 1,
+ status: ChangeStatus.NEW,
+ },
+ ];
+
+ test('clear and empties', () => {
+ element._relatedResponse = {changes: relatedChanges};
+ element._submittedTogether = {
+ changes,
+ non_visible_changes: 0,
+ };
+ element._conflicts = changes;
+ element._cherryPicks = changes;
+ element._sameTopic = changes;
+
+ element.hidden = false;
+ element.clear();
+ assert.isTrue(element.hidden);
+ assert.equal(element._relatedResponse.changes.length, 0);
+ assert.equal(element._submittedTogether?.changes.length, 0);
+ assert.equal(element._conflicts.length, 0);
+ assert.equal(element._cherryPicks.length, 0);
+ assert.equal(element._sameTopic?.length, 0);
+ });
+
+ test('update fires', () => {
+ const updateHandler = sinon.stub();
+ element.addEventListener('update', updateHandler);
+
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isTrue(element.hidden);
+ assert.isFalse(updateHandler.called);
+
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ changes
+ );
+ assert.isFalse(element.hidden);
+ assert.isTrue(updateHandler.called);
+ updateHandler.reset();
+
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isTrue(element.hidden);
+ assert.isFalse(updateHandler.called);
+
+ element._resultsChanged(
+ {changes: []},
+ {changes, non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+ assert.isTrue(updateHandler.called);
+ updateHandler.reset();
+
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 1},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+ assert.isTrue(updateHandler.called);
+ });
+
+ suite('hiding and unhiding', () => {
+ test('related response', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged(
+ {changes: relatedChanges},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+ });
+
+ test('submitted together', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged(
+ {changes: []},
+ {changes, non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+ });
+
+ test('conflicts', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ changes,
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+ });
+
+ test('cherrypicks', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ changes,
+ []
+ );
+ assert.isFalse(element.hidden);
+ });
+
+ test('same topic', () => {
+ assert.isTrue(element.hidden);
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ changes
+ );
+ assert.isFalse(element.hidden);
+ });
+ });
+ });
+
+ test('_computeChangeURL uses GerritNav', () => {
+ const getUrlStub = sinon.stub(GerritNav, 'getUrlForChangeById');
+ element._computeChangeURL(
+ 123 as NumericChangeId,
+ 'abc/def' as RepoName,
+ 12 as PatchSetNum
+ );
+ assert.isTrue(getUrlStub.called);
+ });
+
+ suite('submitted together changes', () => {
+ const change: ChangeInfo = {
+ ...createChange(),
+ project: 'foo/bar' as RepoName,
+ change_id: 'Ideadbeef' as ChangeId,
+ status: ChangeStatus.NEW,
+ };
+
+ test('_computeSubmittedTogetherClass', () => {
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass(undefined),
+ 'hidden'
+ );
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass({
+ changes: [],
+ non_visible_changes: 0,
+ }),
+ 'hidden'
+ );
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass({
+ changes: [change],
+ non_visible_changes: 0,
+ }),
+ ''
+ );
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass({
+ changes: [],
+ non_visible_changes: 0,
+ }),
+ 'hidden'
+ );
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass({
+ changes: [],
+ non_visible_changes: 1,
+ }),
+ ''
+ );
+ assert.strictEqual(
+ element._computeSubmittedTogetherClass({
+ changes: [],
+ non_visible_changes: 1,
+ }),
+ ''
+ );
+ });
+
+ test('no submitted together changes', () => {
+ flush();
+ assert.include(element.$.submittedTogether.className, 'hidden');
+ });
+
+ test('no non-visible submitted together changes', () => {
+ element._submittedTogether = {changes: [change], non_visible_changes: 0};
+ flush();
+ assert.notInclude(element.$.submittedTogether.className, 'hidden');
+ assert.isUndefined(query(element, '.note'));
+ });
+
+ test('no visible submitted together changes', () => {
+ // Technically this should never happen, but worth asserting the logic.
+ element._submittedTogether = {changes: [], non_visible_changes: 1};
+ flush();
+ assert.notInclude(element.$.submittedTogether.className, 'hidden');
+ assert.strictEqual(
+ queryAndAssert<HTMLDivElement>(element, '.note').innerText.trim(),
+ '(+ 1 non-visible change)'
+ );
+ });
+
+ test('visible and non-visible submitted together changes', () => {
+ element._submittedTogether = {changes: [change], non_visible_changes: 2};
+ flush();
+ assert.notInclude(element.$.submittedTogether.className, 'hidden');
+ assert.strictEqual(
+ queryAndAssert<HTMLDivElement>(element, '.note').innerText.trim(),
+ '(+ 2 non-visible changes)'
+ );
+ });
+ });
+
+ suite('gr-related-changes-list plugin tests', () => {
+ let element: GrRelatedChangesList;
+
+ setup(() => {
+ resetPlugins();
+ element = basicFixture.instantiate();
+ });
+
+ teardown(() => {
+ resetPlugins();
+ });
+
+ test('endpoint params', done => {
+ element.change = {...createParsedChange(), labels: {}};
+ interface RelatedChangesListGrEndpointDecorator
+ extends GrEndpointDecorator {
+ plugin: PluginApi;
+ change: ParsedChangeInfo;
+ }
+ let hookEl: RelatedChangesListGrEndpointDecorator;
+ let plugin: PluginApi;
+ pluginApi.install(
+ p => {
+ plugin = p;
+ plugin
+ .hook('related-changes-section')
+ .getLastAttached()
+ .then(el => (hookEl = el as RelatedChangesListGrEndpointDecorator));
+ },
+ '0.1',
+ 'http://some/plugins/url1.js'
+ );
+ getPluginLoader().loadPlugins([]);
+ flush(() => {
+ assert.strictEqual(hookEl.plugin, plugin);
+ assert.strictEqual(hookEl.change, element.change);
+ done();
+ });
+ });
+ });
+
+ test('hiding and unhiding', done => {
+ element.change = {...createParsedChange(), labels: {}};
+ let hookEl: HTMLElement;
+ let plugin;
+
+ // No changes, and no plugin. The element is still hidden.
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isTrue(element.hidden);
+ pluginApi.install(
+ p => {
+ plugin = p;
+ plugin
+ .hook('related-changes-section')
+ .getLastAttached()
+ .then(el => (hookEl = el));
+ },
+ '0.1',
+ 'http://some/plugins/url2.js'
+ );
+ getPluginLoader().loadPlugins([]);
+ flush(() => {
+ // No changes, and plugin without hidden attribute. So it's visible.
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+
+ // No changes, but plugin with true hidden attribute. So it's invisible.
+ hookEl.hidden = true;
+
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isTrue(element.hidden);
+
+ // No changes, and plugin with false hidden attribute. So it's visible.
+ hookEl.hidden = false;
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ []
+ );
+ assert.isFalse(element.hidden);
+
+ // Hiding triggered by plugin itself
+ hookEl.hidden = true;
+ hookEl.dispatchEvent(
+ new CustomEvent('new-section-loaded', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(element.hidden);
+
+ // Unhiding triggered by plugin itself
+ hookEl.hidden = false;
+ hookEl.dispatchEvent(
+ new CustomEvent('new-section-loaded', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isFalse(element.hidden);
+
+ // Hiding plugin keeps list visible, if there are changes
+ hookEl.hidden = false;
+ const change = createChange();
+ element._sameTopic = [change];
+ element._resultsChanged(
+ {changes: []},
+ {changes: [], non_visible_changes: 0},
+ [],
+ [],
+ [change]
+ );
+ assert.isFalse(element.hidden);
+ hookEl.hidden = true;
+ hookEl.dispatchEvent(
+ new CustomEvent('new-section-loaded', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isFalse(element.hidden);
+
+ done();
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
index b09510ba..5f35fd3 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
@@ -16,12 +16,10 @@
*/
import '../../../test/common-test-setup-karma.js';
-import {resetPlugins} from '../../../test/test-utils.js';
+import {resetPlugins, stubRestApi} from '../../../test/test-utils.js';
import './gr-reply-dialog.js';
-import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-reply-dialog');
const pluginApi = _testOnly_initGerritPluginApi();
@@ -75,7 +73,6 @@
changeNum = 42;
patchNum = 1;
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getAccount').returns(Promise.resolve({_account_id: 42}));
element = basicFixture.instantiate();
@@ -106,7 +103,7 @@
assert.isTrue(sendStub.called);
});
- test('lgtm plugin', done => {
+ test('lgtm plugin', async () => {
resetPlugins();
pluginApi.install(plugin => {
const replyApi = plugin.changeReply();
@@ -123,20 +120,17 @@
element = basicFixture.instantiate();
setupElement(element);
getPluginLoader().loadPlugins([]);
- getPluginLoader().awaitPluginsLoaded()
- .then(() => {
- flush(() => {
- const textarea = element.$.textarea.getNativeTextarea();
- textarea.value = 'LGTM';
- textarea.dispatchEvent(new CustomEvent(
- 'input', {bubbles: true, composed: true}));
- const labelScoreRows = dom(element.$.labelScores.root)
- .querySelector('gr-label-score-row[name="Code-Review"]');
- const selectedBtn = dom(labelScoreRows.root)
- .querySelector('gr-button[data-value="+1"].iron-selected');
- assert.isOk(selectedBtn);
- done();
- });
- });
+ await getPluginLoader().awaitPluginsLoaded();
+ await flush();
+ const textarea = element.$.textarea.getNativeTextarea();
+ textarea.value = 'LGTM';
+ textarea.dispatchEvent(new CustomEvent(
+ 'input', {bubbles: true, composed: true}));
+ await flush();
+ const labelScoreRows = element.$.labelScores.shadowRoot
+ .querySelector('gr-label-score-row[name="Code-Review"]');
+ const selectedBtn = labelScoreRows.shadowRoot
+ .querySelector('gr-button[data-value="+1"].iron-selected');
+ assert.isOk(selectedBtn);
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index a8e89b6..2cabf90 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -21,13 +21,10 @@
import '../../shared/gr-button/gr-button';
import '../../shared/gr-formatted-text/gr-formatted-text';
import '../../shared/gr-overlay/gr-overlay';
-import '../../shared/gr-storage/gr-storage';
import '../../shared/gr-account-list/gr-account-list';
import '../gr-label-scores/gr-label-scores';
import '../gr-thread-list/gr-thread-list';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-reply-dialog_html';
import {
@@ -96,21 +93,27 @@
assertNever,
containsAll,
} from '../../../utils/common-util';
-import {CommentThread} from '../../../utils/comment-util';
+import {CommentThread, isUnresolved} from '../../../utils/comment-util';
import {GrTextarea} from '../../shared/gr-textarea/gr-textarea';
import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
-import {GrStorage, StorageLocation} from '../../shared/gr-storage/gr-storage';
import {isAttentionSetEnabled} from '../../../utils/attention-set-util';
import {
CODE_REVIEW,
getApprovalInfo,
getMaxAccounts,
} from '../../../utils/label-util';
-import {isUnresolved} from '../../../utils/comment-util';
import {pluralize} from '../../../utils/string-util';
-import {fireAlert, fireEvent, fireServerError} from '../../../utils/event-util';
+import {
+ fireAlert,
+ fireEvent,
+ fireIronAnnounce,
+ fireServerError,
+} from '../../../utils/event-util';
import {ErrorCallback} from '../../../api/rest';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {StorageLocation} from '../../../services/storage/gr-storage';
+import {Timing} from '../../../constants/reporting';
const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
@@ -146,8 +149,6 @@
const EMPTY_REPLY_MESSAGE = 'Cannot send an empty reply.';
-const SEND_REPLY_TIMING_LABEL = 'SendReply';
-
interface PendingRemovals {
CC: (AccountInfoInput | GroupInfoInput)[];
REVIEWER: (AccountInfoInput | GroupInfoInput)[];
@@ -169,12 +170,8 @@
};
}
-const DEBOUNCER_STORE = 'store';
-
@customElement('gr-reply-dialog')
-export class GrReplyDialog extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrReplyDialog extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -375,10 +372,12 @@
private readonly restApiService = appContext.restApiService;
- private readonly storage = new GrStorage();
+ private readonly storage = appContext.storageService;
private readonly jsAPI = appContext.jsApiService;
+ private storeTask?: DelayedTask;
+
get keyBindings() {
return {
esc: '_handleEscKey',
@@ -395,8 +394,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
((IronA11yAnnouncer as unknown) as FixIronA11yAnnouncer).requestAvailability();
this._getAccount().then(account => {
if (account) this._account = account;
@@ -429,8 +428,9 @@
}
/** @override */
- detached() {
- this.cancelDebouncer(DEBOUNCER_STORE);
+ disconnectedCallback() {
+ this.storeTask?.cancel();
+ super.disconnectedCallback();
}
open(focusTarget?: FocusTarget) {
@@ -642,7 +642,7 @@
includeComments: boolean,
startReview: boolean
): Promise<Map<AccountId | EmailAddress, boolean>> {
- this.reporting.time(SEND_REPLY_TIMING_LABEL);
+ this.reporting.time(Timing.SEND_REPLY);
const labels = this.$.labelScores.getLabelValues();
const reviewInput: ReviewInput = {
@@ -732,7 +732,7 @@
bubbles: false,
})
);
- this.fire('iron-announce', {text: 'Reply sent'}, {bubbles: true});
+ fireIronAnnounce(this, 'Reply sent');
return accountAdditions;
})
.then(result => {
@@ -752,13 +752,13 @@
}
if (section === FocusTarget.BODY) {
const textarea = this.$.textarea;
- textarea.async(() => textarea.getNativeTextarea().focus());
+ setTimeout(() => textarea.getNativeTextarea().focus());
} else if (section === FocusTarget.REVIEWERS) {
const reviewerEntry = this.$.reviewers.focusStart;
- reviewerEntry.async(() => reviewerEntry.focus());
+ setTimeout(() => reviewerEntry.focus());
} else if (section === FocusTarget.CCS) {
const ccEntry = this.$.ccs.focusStart;
- ccEntry.async(() => ccEntry.focus());
+ setTimeout(() => ccEntry.focus());
}
}
@@ -1339,8 +1339,8 @@
}
_draftChanged(newDraft: string, oldDraft?: string) {
- this.debounce(
- DEBOUNCER_STORE,
+ this.storeTask = debounce(
+ this.storeTask,
() => {
if (!newDraft.length && oldDraft) {
// If the draft has been modified to be empty, then erase the storage
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index 79569bc..f458994 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -270,9 +270,7 @@
[[_pendingConfirmationDetails.group.name]]
</span>
has
- <span class="groupSize">
- [[_pendingConfirmationDetails.count]]
- </span>
+ <span class="groupSize"> [[_pendingConfirmationDetails.count]] </span>
members.
<br />
Are you sure you want to add them all?
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
index 0575239..c1e2564 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
@@ -18,7 +18,7 @@
import '../../../test/common-test-setup-karma.js';
import {IronOverlayManager} from '@polymer/iron-overlay-behavior/iron-overlay-manager.js';
import './gr-reply-dialog.js';
-import {mockPromise} from '../../../test/test-utils.js';
+import {mockPromise, stubStorage} from '../../../test/test-utils.js';
import {SpecialFilePath} from '../../../constants/constants.js';
import {appContext} from '../../../services/app-context.js';
import {addListenerForTest} from '../../../test/test-utils.js';
@@ -65,7 +65,6 @@
changeNum = 42;
patchNum = 1;
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getAccount').returns(Promise.resolve({}));
stubRestApi('getChange').returns(Promise.resolve({}));
stubRestApi('getChangeSuggestedReviewers').returns(Promise.resolve([]));
@@ -114,9 +113,9 @@
],
};
- getDraftCommentStub = sinon.stub(element.storage, 'getDraftComment');
- setDraftCommentStub = sinon.stub(element.storage, 'setDraftComment');
- eraseDraftCommentStub = sinon.stub(element.storage, 'eraseDraftComment');
+ getDraftCommentStub = stubStorage('getDraftComment');
+ setDraftCommentStub = stubStorage('setDraftComment');
+ eraseDraftCommentStub = stubStorage('eraseDraftComment');
// sinon.stub(patchSetUtilMockProxy, 'fetchChangeUpdates')
// .returns(Promise.resolve({isLatest: true}));
@@ -610,7 +609,7 @@
return false;
}
- function testConfirmationDialog(done, cc) {
+ async function testConfirmationDialog(cc) {
const yesButton = element
.shadowRoot
.querySelector('.reviewerConfirmationButtons gr-button:first-child');
@@ -652,95 +651,90 @@
element._pendingConfirmationDetails);
}
- observer
- .then(() => {
- assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
- observer = overlayObserver('closed');
- const expected = 'Group name has 10 members';
- assert.notEqual(
- element.$.reviewerConfirmationOverlay.innerText
- .indexOf(expected),
- -1);
- MockInteractions.tap(noButton); // close the overlay
- return observer;
- }).then(() => {
- assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
+ await observer;
+ assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
+ observer = overlayObserver('closed');
+ const expected = 'Group name has 10 members';
+ assert.notEqual(
+ element.$.reviewerConfirmationOverlay.innerText
+ .indexOf(expected),
+ -1);
+ MockInteractions.tap(noButton); // close the overlay
- // We should be focused on account entry input.
- assert.isTrue(
- isFocusInsideElement(
- element.$.reviewers.$.entry.$.input.$.input
- )
- );
+ await observer;
+ assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
- // No reviewer/CC should have been added.
- assert.equal(element.$.ccs.additions().length, 0);
- assert.equal(element.$.reviewers.additions().length, 0);
+ // We should be focused on account entry input.
+ assert.isTrue(
+ isFocusInsideElement(
+ element.$.reviewers.$.entry.$.input.$.input
+ )
+ );
- // Reopen confirmation dialog.
- observer = overlayObserver('opened');
- if (cc) {
- element._ccPendingConfirmation = {
- group,
- count: 10,
- };
- } else {
- element._reviewerPendingConfirmation = {
- group,
- count: 10,
- };
- }
- return observer;
- })
- .then(() => {
- assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
- observer = overlayObserver('closed');
- MockInteractions.tap(yesButton); // Confirm the group.
- return observer;
- })
- .then(() => {
- assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
- const additions = cc ?
- element.$.ccs.additions() :
- element.$.reviewers.additions();
- assert.deepEqual(
- additions,
- [
- {
- group: {
- id: 'id',
- name: 'name',
- confirmed: true,
- _group: true,
- _pendingAdd: true,
- },
- },
- ]);
+ // No reviewer/CC should have been added.
+ assert.equal(element.$.ccs.additions().length, 0);
+ assert.equal(element.$.reviewers.additions().length, 0);
- // We should be focused on account entry input.
- if (cc) {
- assert.isTrue(
- isFocusInsideElement(
- element.$.ccs.$.entry.$.input.$.input
- )
- );
- } else {
- assert.isTrue(
- isFocusInsideElement(
- element.$.reviewers.$.entry.$.input.$.input
- )
- );
- }
- })
- .then(done);
+ // Reopen confirmation dialog.
+ observer = overlayObserver('opened');
+ if (cc) {
+ element._ccPendingConfirmation = {
+ group,
+ count: 10,
+ };
+ } else {
+ element._reviewerPendingConfirmation = {
+ group,
+ count: 10,
+ };
+ }
+
+ await observer;
+ assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
+ observer = overlayObserver('closed');
+ MockInteractions.tap(yesButton); // Confirm the group.
+
+ await observer;
+ assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
+ const additions = cc ?
+ element.$.ccs.additions() :
+ element.$.reviewers.additions();
+ assert.deepEqual(
+ additions,
+ [
+ {
+ group: {
+ id: 'id',
+ name: 'name',
+ confirmed: true,
+ _group: true,
+ _pendingAdd: true,
+ },
+ },
+ ]);
+
+ // We should be focused on account entry input.
+ if (cc) {
+ assert.isTrue(
+ isFocusInsideElement(
+ element.$.ccs.$.entry.$.input.$.input
+ )
+ );
+ } else {
+ assert.isTrue(
+ isFocusInsideElement(
+ element.$.reviewers.$.entry.$.input.$.input
+ )
+ );
+ }
}
- test('cc confirmation', done => {
- testConfirmationDialog(done, true);
+ test('cc confirmation', async () => {
+ testConfirmationDialog(true);
});
- test('reviewer confirmation', done => {
- testConfirmationDialog(done, false);
+ test('reviewer confirmation', async () => {
+ testConfirmationDialog(false);
});
test('_getStorageLocation', () => {
@@ -802,12 +796,12 @@
const location = element._getStorageLocation();
element.draft = firstEdit;
- element.flushDebouncer('store');
+ element.storeTask.flush();
assert.isTrue(setDraftCommentStub.calledWith(location, firstEdit));
element.draft = '';
- element.flushDebouncer('store');
+ element.storeTask.flush();
assert.isTrue(eraseDraftCommentStub.calledWith(location));
});
@@ -888,42 +882,37 @@
assert.isFalse(filter({group: cc2}));
});
- test('_focusOn', () => {
+ test('_focusOn', async () => {
sinon.spy(element, '_chooseFocusTarget');
- flush();
- const textareaStub = sinon.stub(element.$.textarea, 'async');
- const reviewerEntryStub = sinon.stub(element.$.reviewers.focusStart,
- 'async');
- const ccStub = sinon.stub(element.$.ccs.focusStart, 'async');
element._focusOn();
+ await flush();
assert.equal(element._chooseFocusTarget.callCount, 1);
- assert.deepEqual(textareaStub.callCount, 1);
- assert.deepEqual(reviewerEntryStub.callCount, 0);
- assert.deepEqual(ccStub.callCount, 0);
+ assert.equal(element.shadowRoot.activeElement.tagName, 'GR-TEXTAREA');
+ assert.equal(element.shadowRoot.activeElement.id, 'textarea');
element._focusOn(element.FocusTarget.ANY);
+ await flush();
assert.equal(element._chooseFocusTarget.callCount, 2);
- assert.deepEqual(textareaStub.callCount, 2);
- assert.deepEqual(reviewerEntryStub.callCount, 0);
- assert.deepEqual(ccStub.callCount, 0);
+ assert.equal(element.shadowRoot.activeElement.tagName, 'GR-TEXTAREA');
+ assert.equal(element.shadowRoot.activeElement.id, 'textarea');
element._focusOn(element.FocusTarget.BODY);
+ await flush();
assert.equal(element._chooseFocusTarget.callCount, 2);
- assert.deepEqual(textareaStub.callCount, 3);
- assert.deepEqual(reviewerEntryStub.callCount, 0);
- assert.deepEqual(ccStub.callCount, 0);
+ assert.equal(element.shadowRoot.activeElement.tagName, 'GR-TEXTAREA');
+ assert.equal(element.shadowRoot.activeElement.id, 'textarea');
element._focusOn(element.FocusTarget.REVIEWERS);
+ await flush();
assert.equal(element._chooseFocusTarget.callCount, 2);
- assert.deepEqual(textareaStub.callCount, 3);
- assert.deepEqual(reviewerEntryStub.callCount, 1);
- assert.deepEqual(ccStub.callCount, 0);
+ assert.equal(element.shadowRoot.activeElement.tagName, 'GR-ACCOUNT-LIST');
+ assert.equal(element.shadowRoot.activeElement.id, 'reviewers');
element._focusOn(element.FocusTarget.CCS);
+ await flush();
assert.equal(element._chooseFocusTarget.callCount, 2);
- assert.deepEqual(textareaStub.callCount, 3);
- assert.deepEqual(reviewerEntryStub.callCount, 1);
- assert.deepEqual(ccStub.callCount, 1);
+ assert.equal(element.shadowRoot.activeElement.tagName, 'GR-ACCOUNT-LIST');
+ assert.equal(element.shadowRoot.activeElement.id, 'ccs');
});
test('_chooseFocusTarget', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
index 30931c3..1fcc332 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
@@ -18,11 +18,9 @@
import '../../shared/gr-button/gr-button';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-reviewer-list_html';
-import {isServiceUser} from '../../../utils/account-util';
+import {isSelf, isServiceUser} from '../../../utils/account-util';
import {hasAttention} from '../../../utils/attention-set-util';
import {customElement, property, computed, observe} from '@polymer/decorators';
import {
@@ -35,6 +33,7 @@
AccountId,
DetailedLabelInfo,
EmailAddress,
+ AccountDetailInfo,
} from '../../../types/common';
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
@@ -45,9 +44,7 @@
import {KnownExperimentId} from '../../../services/flags/flags';
@customElement('gr-reviewer-list')
-export class GrReviewerList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrReviewerList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -62,6 +59,9 @@
change?: ChangeInfo;
@property({type: Object})
+ account?: AccountDetailInfo;
+
+ @property({type: Object})
serverConfig?: ServerInfo;
@property({type: Boolean, reflectToAttribute: true})
@@ -245,10 +245,15 @@
this._reviewers = result
.filter(reviewer => reviewer._account_id !== owner._account_id)
// Sort order:
- // 1. Human users in the attention set.
- // 2. Other human users.
- // 3. Service users.
+ // 1. The user themselves
+ // 2. Human users in the attention set.
+ // 3. Other human users.
+ // 4. Service users.
.sort((r1, r2) => {
+ if (this.account) {
+ if (isSelf(r1, this.account)) return -1;
+ if (isSelf(r2, this.account)) return 1;
+ }
const a1 = hasAttention(serverConfig, r1, this.change!) ? 1 : 0;
const a2 = hasAttention(serverConfig, r2, this.change!) ? 1 : 0;
const s1 = isServiceUser(r1) ? -2 : 0;
@@ -335,3 +340,9 @@
return this.restApiService.removeChangeReviewer(this.change._number, id);
}
}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-reviewer-list': GrReviewerList;
+ }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js
deleted file mode 100644
index f77f736..0000000
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js
+++ /dev/null
@@ -1,400 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-reviewer-list.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-reviewer-list');
-
-suite('gr-reviewer-list tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- element.serverConfig = {};
-
- stubRestApi('getConfig').returns(Promise.resolve({}));
- stubRestApi('removeChangeReviewer').returns(Promise.resolve({ok: true}));
- });
-
- test('controls hidden on immutable element', () => {
- flush();
- element.mutable = false;
- assert.isTrue(element.shadowRoot
- .querySelector('.controlsContainer').hasAttribute('hidden'));
- element.mutable = true;
- assert.isFalse(element.shadowRoot
- .querySelector('.controlsContainer').hasAttribute('hidden'));
- });
-
- test('add reviewer button opens reply dialog', done => {
- element.addEventListener('show-reply-dialog', () => {
- done();
- });
- flush();
- MockInteractions.tap(element.shadowRoot
- .querySelector('.addReviewer'));
- });
-
- test('only show remove for removable reviewers', () => {
- element.mutable = true;
- element.change = {
- owner: {
- _account_id: 1,
- },
- reviewers: {
- REVIEWER: [
- {
- _account_id: 2,
- name: 'Bojack Horseman',
- email: 'SecretariatRulez96@hotmail.com',
- },
- {
- _account_id: 3,
- name: 'Pinky Penguin',
- },
- ],
- CC: [
- {
- _account_id: 4,
- name: 'Diane Nguyen',
- email: 'macarthurfellow2B@juno.com',
- },
- {
- email: 'test@e.mail',
- },
- ],
- },
- removable_reviewers: [
- {
- _account_id: 3,
- name: 'Pinky Penguin',
- },
- {
- _account_id: 4,
- name: 'Diane Nguyen',
- email: 'macarthurfellow2B@juno.com',
- },
- {
- email: 'test@e.mail',
- },
- ],
- };
- flush();
- const chips =
- element.root.querySelectorAll('gr-account-chip');
- assert.equal(chips.length, 4);
-
- for (const el of Array.from(chips)) {
- const accountID = el.account._account_id || el.account.email;
- assert.ok(accountID);
-
- const buttonEl = el.shadowRoot
- .querySelector('gr-button');
- assert.isNotNull(buttonEl);
- if (accountID == 2) {
- assert.isTrue(buttonEl.hasAttribute('hidden'));
- } else {
- assert.isFalse(buttonEl.hasAttribute('hidden'));
- }
- }
- });
-
- suite('_handleRemove', () => {
- let removeReviewerStub;
- let reviewersChangedSpy;
-
- const reviewerWithId = {
- _account_id: 2,
- name: 'Some name',
- };
-
- const reviewerWithIdAndEmail = {
- _account_id: 4,
- name: 'Some other name',
- email: 'example@',
- };
-
- const reviewerWithEmailOnly = {
- email: 'example2@example',
- };
-
- let chips;
-
- setup(() => {
- removeReviewerStub = sinon
- .stub(element, '_removeReviewer')
- .returns(Promise.resolve(new Response({status: 200})));
- element.mutable = true;
-
- const allReviewers = [
- reviewerWithId,
- reviewerWithIdAndEmail,
- reviewerWithEmailOnly,
- ];
-
- element.change = {
- owner: {
- _account_id: 1,
- },
- reviewers: {
- REVIEWER: allReviewers,
- },
- removable_reviewers: allReviewers,
- };
- flush();
- chips = Array.from(element.root.querySelectorAll('gr-account-chip'));
- assert.equal(chips.length, allReviewers.length);
- reviewersChangedSpy = sinon.spy(element, '_reviewersChanged');
- });
-
- test('_handleRemove for account with accountId only', async () => {
- const accountChip = chips.find(chip =>
- chip.account._account_id === reviewerWithId._account_id
- );
- accountChip._handleRemoveTap(new MouseEvent('click'));
- await flush();
- assert.isTrue(removeReviewerStub.calledOnce);
- assert.isTrue(removeReviewerStub.calledWith(reviewerWithId._account_id));
- assert.isTrue(reviewersChangedSpy.called);
- expect(element.change.reviewers.REVIEWER).to.have.deep.members([
- reviewerWithIdAndEmail,
- reviewerWithEmailOnly,
- ]);
- });
-
- test('_handleRemove for account with accountId and email', async () => {
- const accountChip = chips.find(chip =>
- chip.account._account_id === reviewerWithIdAndEmail._account_id
- );
- accountChip._handleRemoveTap(new MouseEvent('click'));
- await flush();
- assert.isTrue(removeReviewerStub.calledOnce);
- assert.isTrue(
- removeReviewerStub.calledWith(reviewerWithIdAndEmail._account_id));
- assert.isTrue(reviewersChangedSpy.called);
- expect(element.change.reviewers.REVIEWER).to.have.deep.members([
- reviewerWithId,
- reviewerWithEmailOnly,
- ]);
- });
-
- test('_handleRemove for account with email only', async () => {
- const accountChip = chips.find(
- chip => chip.account.email === reviewerWithEmailOnly.email
- );
- accountChip._handleRemoveTap(new MouseEvent('click'));
- await flush();
- assert.isTrue(removeReviewerStub.calledOnce);
- assert.isTrue(removeReviewerStub.calledWith(reviewerWithEmailOnly.email));
- assert.isTrue(reviewersChangedSpy.called);
- expect(element.change.reviewers.REVIEWER).to.have.deep.members([
- reviewerWithId,
- reviewerWithIdAndEmail,
- ]);
- });
- });
-
- test('tracking reviewers and ccs', () => {
- let counter = 0;
- function makeAccount() {
- return {_account_id: counter++};
- }
-
- const owner = makeAccount();
- const reviewer = makeAccount();
- const cc = makeAccount();
- const reviewers = {
- REMOVED: [makeAccount()],
- REVIEWER: [owner, reviewer],
- CC: [owner, cc],
- };
-
- element.ccsOnly = false;
- element.reviewersOnly = false;
- element.change = {
- owner,
- reviewers,
- };
- assert.deepEqual(element._reviewers, [reviewer, cc]);
-
- element.reviewersOnly = true;
- element.change = {
- owner,
- reviewers,
- };
- assert.deepEqual(element._reviewers, [reviewer]);
-
- element.ccsOnly = true;
- element.reviewersOnly = false;
- element.change = {
- owner,
- reviewers,
- };
- assert.deepEqual(element._reviewers, [cc]);
- });
-
- test('_handleAddTap passes mode with event', () => {
- const fireStub = sinon.stub(element, 'dispatchEvent');
- const e = {preventDefault() {}};
-
- element.ccsOnly = false;
- element.reviewersOnly = false;
- element._handleAddTap(e);
- assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
- assert.deepEqual(fireStub.lastCall.args[0].detail, {value: {
- reviewersOnly: false,
- ccsOnly: false,
- }});
-
- element.reviewersOnly = true;
- element._handleAddTap(e);
- assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
- assert.deepEqual(
- fireStub.lastCall.args[0].detail,
- {value: {reviewersOnly: true, ccsOnly: false}});
-
- element.ccsOnly = true;
- element.reviewersOnly = false;
- element._handleAddTap(e);
- assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
- assert.deepEqual(fireStub.lastCall.args[0].detail,
- {value: {ccsOnly: true, reviewersOnly: false}});
- });
-
- test('dont show all reviewers button with 4 reviewers', () => {
- const reviewers = [];
- element.maxReviewersDisplayed = 3;
- for (let i = 0; i < 4; i++) {
- reviewers.push(
- {email: i+'reviewer@google.com', name: 'reviewer-' + i});
- }
- element.ccsOnly = true;
-
- element.change = {
- owner: {
- _account_id: 1,
- },
- reviewers: {
- CC: reviewers,
- },
- };
- assert.equal(element._hiddenReviewerCount, 0);
- assert.equal(element._displayedReviewers.length, 4);
- assert.equal(element._reviewers.length, 4);
- assert.isTrue(element.shadowRoot
- .querySelector('.hiddenReviewers').hidden);
- });
-
- test('show all reviewers button with 9 reviewers', () => {
- const reviewers = [];
- for (let i = 0; i < 9; i++) {
- reviewers.push(
- {email: i+'reviewer@google.com', name: 'reviewer-' + i});
- }
- element.ccsOnly = true;
-
- element.change = {
- owner: {
- _account_id: 1,
- },
- reviewers: {
- CC: reviewers,
- },
- };
- assert.equal(element._hiddenReviewerCount, 3);
- assert.equal(element._displayedReviewers.length, 6);
- assert.equal(element._reviewers.length, 9);
- assert.isFalse(element.shadowRoot
- .querySelector('.hiddenReviewers').hidden);
- });
-
- test('show all reviewers button', () => {
- const reviewers = [];
- for (let i = 0; i < 100; i++) {
- reviewers.push(
- {email: i+'reviewer@google.com', name: 'reviewer-' + i});
- }
- element.ccsOnly = true;
-
- element.change = {
- owner: {
- _account_id: 1,
- },
- reviewers: {
- CC: reviewers,
- },
- };
- assert.equal(element._hiddenReviewerCount, 94);
- assert.equal(element._displayedReviewers.length, 6);
- assert.equal(element._reviewers.length, 100);
- assert.isFalse(element.shadowRoot
- .querySelector('.hiddenReviewers').hidden);
-
- MockInteractions.tap(element.shadowRoot
- .querySelector('.hiddenReviewers'));
-
- assert.equal(element._hiddenReviewerCount, 0);
- assert.equal(element._displayedReviewers.length, 100);
- assert.equal(element._reviewers.length, 100);
- assert.isTrue(element.shadowRoot
- .querySelector('.hiddenReviewers').hidden);
- });
-
- test('votable labels', () => {
- const change = {
- labels: {
- Foo: {
- all: [{_account_id: 7, permitted_voting_range: {max: 2}}],
- },
- Bar: {
- all: [{_account_id: 1, permitted_voting_range: {max: 1}},
- {_account_id: 7, permitted_voting_range: {max: 1}}],
- },
- FooBar: {
- all: [{_account_id: 7, value: 0}],
- },
- },
- permitted_labels: {
- Foo: ['-1', ' 0', '+1', '+2'],
- FooBar: ['-1', ' 0'],
- },
- };
- assert.strictEqual(
- element._computeVoteableText({_account_id: 1}, change),
- 'Bar');
- assert.strictEqual(
- element._computeVoteableText({_account_id: 7}, change),
- 'Foo: +2, Bar, FooBar');
- assert.strictEqual(
- element._computeVoteableText({_account_id: 2}, change),
- '');
- });
-
- test('fails gracefully when all is not included', () => {
- const change = {
- labels: {Foo: {}},
- permitted_labels: {
- Foo: ['-1', ' 0', '+1', '+2'],
- },
- };
- assert.strictEqual(
- element._computeVoteableText({_account_id: 1}, change), '');
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
new file mode 100644
index 0000000..0a709e1
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
@@ -0,0 +1,477 @@
+/**
+ * @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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-reviewer-list';
+import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {GrReviewerList} from './gr-reviewer-list';
+import {
+ createAccountDetailWithId,
+ createChange,
+ createServerInfo,
+} from '../../../test/test-data-generators';
+import {tap} from '@polymer/iron-test-helpers/mock-interactions';
+import {GrButton} from '../../shared/gr-button/gr-button';
+import {AccountId, EmailAddress} from '../../../types/common';
+import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
+
+const basicFixture = fixtureFromElement('gr-reviewer-list');
+
+suite('gr-reviewer-list tests', () => {
+ let element: GrReviewerList;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ element.serverConfig = createServerInfo();
+
+ stubRestApi('removeChangeReviewer').returns(
+ Promise.resolve({...new Response(), ok: true})
+ );
+ });
+
+ test('controls hidden on immutable element', () => {
+ flush();
+ element.mutable = false;
+ assert.isTrue(
+ queryAndAssert(element, '.controlsContainer').hasAttribute('hidden')
+ );
+ element.mutable = true;
+ assert.isFalse(
+ queryAndAssert(element, '.controlsContainer').hasAttribute('hidden')
+ );
+ });
+
+ test('add reviewer button opens reply dialog', done => {
+ element.addEventListener('show-reply-dialog', () => {
+ done();
+ });
+ flush();
+ tap(queryAndAssert(element, '.addReviewer'));
+ });
+
+ test('only show remove for removable reviewers', () => {
+ element.mutable = true;
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(1),
+ },
+ reviewers: {
+ REVIEWER: [
+ {
+ ...createAccountDetailWithId(2),
+ name: 'Bojack Horseman',
+ email: 'SecretariatRulez96@hotmail.com' as EmailAddress,
+ },
+ {
+ _account_id: 3 as AccountId,
+ name: 'Pinky Penguin',
+ },
+ ],
+ CC: [
+ {
+ ...createAccountDetailWithId(4),
+ name: 'Diane Nguyen',
+ email: 'macarthurfellow2B@juno.com' as EmailAddress,
+ },
+ {
+ email: 'test@e.mail' as EmailAddress,
+ },
+ ],
+ },
+ removable_reviewers: [
+ {
+ _account_id: 3 as AccountId,
+ name: 'Pinky Penguin',
+ },
+ {
+ ...createAccountDetailWithId(4),
+ name: 'Diane Nguyen',
+ email: 'macarthurfellow2B@juno.com' as EmailAddress,
+ },
+ {
+ email: 'test@e.mail' as EmailAddress,
+ },
+ ],
+ };
+ flush();
+ const chips = element.root!.querySelectorAll('gr-account-chip');
+ assert.equal(chips.length, 4);
+
+ for (const el of Array.from(chips)) {
+ const accountID = el.account!._account_id || el.account!.email;
+ assert.ok(accountID);
+
+ const buttonEl = queryAndAssert(el, 'gr-button');
+ if (accountID === 2) {
+ assert.isTrue(buttonEl.hasAttribute('hidden'));
+ } else {
+ assert.isFalse(buttonEl.hasAttribute('hidden'));
+ }
+ }
+ });
+
+ suite('_handleRemove', () => {
+ let removeReviewerStub: sinon.SinonStub;
+ let reviewersChangedSpy: sinon.SinonSpy;
+
+ const reviewerWithId = {
+ ...createAccountDetailWithId(2),
+ name: 'Some name',
+ };
+
+ const reviewerWithIdAndEmail = {
+ ...createAccountDetailWithId(4),
+ name: 'Some other name',
+ email: 'example@' as EmailAddress,
+ };
+
+ const reviewerWithEmailOnly = {
+ email: 'example2@example' as EmailAddress,
+ };
+
+ let chips: GrAccountChip[];
+
+ setup(() => {
+ removeReviewerStub = sinon
+ .stub(element, '_removeReviewer')
+ .returns(Promise.resolve(new Response()));
+ element.mutable = true;
+
+ const allReviewers = [
+ reviewerWithId,
+ reviewerWithIdAndEmail,
+ reviewerWithEmailOnly,
+ ];
+
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(1),
+ },
+ reviewers: {
+ REVIEWER: allReviewers,
+ },
+ removable_reviewers: allReviewers,
+ };
+ flush();
+ chips = Array.from(element.root!.querySelectorAll('gr-account-chip'));
+ assert.equal(chips.length, allReviewers.length);
+ reviewersChangedSpy = sinon.spy(element, '_reviewersChanged');
+ });
+
+ test('_handleRemove for account with accountId only', async () => {
+ const accountChip = chips.find(
+ chip => chip.account!._account_id === reviewerWithId._account_id
+ );
+ accountChip!._handleRemoveTap(new MouseEvent('click'));
+ await flush();
+ assert.isTrue(removeReviewerStub.calledOnce);
+ assert.isTrue(removeReviewerStub.calledWith(reviewerWithId._account_id));
+ assert.isTrue(reviewersChangedSpy.called);
+ expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+ reviewerWithIdAndEmail,
+ reviewerWithEmailOnly,
+ ]);
+ });
+
+ test('_handleRemove for account with accountId and email', async () => {
+ const accountChip = chips.find(
+ chip => chip.account!._account_id === reviewerWithIdAndEmail._account_id
+ );
+ accountChip!._handleRemoveTap(new MouseEvent('click'));
+ await flush();
+ assert.isTrue(removeReviewerStub.calledOnce);
+ assert.isTrue(
+ removeReviewerStub.calledWith(reviewerWithIdAndEmail._account_id)
+ );
+ assert.isTrue(reviewersChangedSpy.called);
+ expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+ reviewerWithId,
+ reviewerWithEmailOnly,
+ ]);
+ });
+
+ test('_handleRemove for account with email only', async () => {
+ const accountChip = chips.find(
+ chip => chip.account!.email === reviewerWithEmailOnly.email
+ );
+ accountChip!._handleRemoveTap(new MouseEvent('click'));
+ await flush();
+ assert.isTrue(removeReviewerStub.calledOnce);
+ assert.isTrue(removeReviewerStub.calledWith(reviewerWithEmailOnly.email));
+ assert.isTrue(reviewersChangedSpy.called);
+ expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+ reviewerWithId,
+ reviewerWithIdAndEmail,
+ ]);
+ });
+ });
+
+ test('tracking reviewers and ccs', () => {
+ let counter = 0;
+ function makeAccount() {
+ return {_account_id: counter++ as AccountId};
+ }
+
+ const owner = makeAccount();
+ const reviewer = makeAccount();
+ const cc = makeAccount();
+ const reviewers = {
+ REMOVED: [makeAccount()],
+ REVIEWER: [owner, reviewer],
+ CC: [owner, cc],
+ };
+
+ element.ccsOnly = false;
+ element.reviewersOnly = false;
+ element.change = {
+ ...createChange(),
+ owner,
+ reviewers,
+ };
+ assert.deepEqual(element._reviewers, [reviewer, cc]);
+
+ element.reviewersOnly = true;
+ element.change = {
+ ...createChange(),
+ owner,
+ reviewers,
+ };
+ assert.deepEqual(element._reviewers, [reviewer]);
+
+ element.ccsOnly = true;
+ element.reviewersOnly = false;
+ element.change = {
+ ...createChange(),
+ owner,
+ reviewers,
+ };
+ assert.deepEqual(element._reviewers, [cc]);
+ });
+
+ test('_handleAddTap passes mode with event', () => {
+ const fireStub = sinon.stub(element, 'dispatchEvent');
+ const e = {...new Event(''), preventDefault() {}};
+
+ element.ccsOnly = false;
+ element.reviewersOnly = false;
+ element._handleAddTap(e);
+ assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+ assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+ value: {
+ reviewersOnly: false,
+ ccsOnly: false,
+ },
+ });
+
+ element.reviewersOnly = true;
+ element._handleAddTap(e);
+ assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+ assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+ value: {reviewersOnly: true, ccsOnly: false},
+ });
+
+ element.ccsOnly = true;
+ element.reviewersOnly = false;
+ element._handleAddTap(e);
+ assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+ assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+ value: {ccsOnly: true, reviewersOnly: false},
+ });
+ });
+
+ test('dont show all reviewers button with 4 reviewers', () => {
+ const reviewers = [];
+ for (let i = 0; i < 4; i++) {
+ reviewers.push({
+ ...createAccountDetailWithId(i),
+ email: `${i}reviewer@google.com` as EmailAddress,
+ name: `reviewer${i}`,
+ });
+ }
+ element.ccsOnly = true;
+
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(111),
+ },
+ reviewers: {
+ CC: reviewers,
+ },
+ };
+ assert.equal(element._hiddenReviewerCount, 0);
+ assert.equal(element._displayedReviewers.length, 4);
+ assert.equal(element._reviewers.length, 4);
+ assert.isTrue(
+ (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+ );
+ });
+
+ test('account owner comes first in list of reviewers', () => {
+ const reviewers = [];
+ for (let i = 0; i < 4; i++) {
+ reviewers.push({
+ ...createAccountDetailWithId(i),
+ email: `${i}reviewer@google.com` as EmailAddress,
+ name: `reviewer${i}`,
+ });
+ }
+ element.reviewersOnly = true;
+ element.account = {
+ ...createAccountDetailWithId(1),
+ };
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(11),
+ },
+ reviewers: {
+ REVIEWER: reviewers,
+ },
+ };
+ flush();
+ assert.equal(element._displayedReviewers[0]._account_id, 1 as AccountId);
+ });
+
+ test('show all reviewers button with 9 reviewers', () => {
+ const reviewers = [];
+ for (let i = 0; i < 9; i++) {
+ reviewers.push({
+ ...createAccountDetailWithId(i),
+ email: `${i}reviewer@google.com` as EmailAddress,
+ name: `reviewer${i}`,
+ });
+ }
+ element.ccsOnly = true;
+
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(111),
+ },
+ reviewers: {
+ CC: reviewers,
+ },
+ };
+ assert.equal(element._hiddenReviewerCount, 3);
+ assert.equal(element._displayedReviewers.length, 6);
+ assert.equal(element._reviewers.length, 9);
+ assert.isFalse(
+ (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+ );
+ });
+
+ test('show all reviewers button', () => {
+ const reviewers = [];
+ for (let i = 0; i < 100; i++) {
+ reviewers.push({
+ ...createAccountDetailWithId(i),
+ email: `${i}reviewer@google.com` as EmailAddress,
+ name: `reviewer${i}`,
+ });
+ }
+ element.ccsOnly = true;
+
+ element.change = {
+ ...createChange(),
+ owner: {
+ ...createAccountDetailWithId(111),
+ },
+ reviewers: {
+ CC: reviewers,
+ },
+ };
+ assert.equal(element._hiddenReviewerCount, 94);
+ assert.equal(element._displayedReviewers.length, 6);
+ assert.equal(element._reviewers.length, 100);
+ assert.isFalse(
+ (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+ );
+
+ tap(queryAndAssert(element, '.hiddenReviewers'));
+
+ assert.equal(element._hiddenReviewerCount, 0);
+ assert.equal(element._displayedReviewers.length, 100);
+ assert.equal(element._reviewers.length, 100);
+ assert.isTrue(
+ (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+ );
+ });
+
+ test('votable labels', () => {
+ const change = {
+ ...createChange(),
+ labels: {
+ Foo: {
+ all: [
+ {
+ _account_id: 7 as AccountId,
+ permitted_voting_range: {max: 2, min: 0},
+ },
+ ],
+ },
+ Bar: {
+ all: [
+ {
+ ...createAccountDetailWithId(1),
+ permitted_voting_range: {max: 1, min: 0},
+ },
+ {
+ _account_id: 7 as AccountId,
+ permitted_voting_range: {max: 1, min: 0},
+ },
+ ],
+ },
+ FooBar: {
+ all: [{_account_id: 7 as AccountId, value: 0}],
+ },
+ },
+ permitted_labels: {
+ Foo: ['-1', ' 0', '+1', '+2'],
+ FooBar: ['-1', ' 0'],
+ },
+ };
+ assert.strictEqual(
+ element._computeVoteableText({...createAccountDetailWithId(1)}, change),
+ 'Bar'
+ );
+ assert.strictEqual(
+ element._computeVoteableText({...createAccountDetailWithId(7)}, change),
+ 'Foo: +2, Bar, FooBar'
+ );
+ assert.strictEqual(
+ element._computeVoteableText({...createAccountDetailWithId(2)}, change),
+ ''
+ );
+ });
+
+ test('fails gracefully when all is not included', () => {
+ const change = {
+ ...createChange(),
+ labels: {Foo: {}},
+ permitted_labels: {
+ Foo: ['-1', ' 0', '+1', '+2'],
+ },
+ };
+ assert.strictEqual(
+ element._computeVoteableText({...createAccountDetailWithId(1)}, change),
+ ''
+ );
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
index f0ec7cd..99abf89 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
@@ -18,8 +18,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-comment-thread/gr-comment-thread';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-thread-list_html';
import {parseDate} from '../../../utils/date-util';
@@ -57,9 +55,7 @@
}
@customElement('gr-thread-list')
-export class GrThreadList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrThreadList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -512,19 +508,29 @@
oldValue?: CommentTabState
) {
if (!newValue || newValue === oldValue) return;
+ let focusTo: string | undefined;
switch (newValue) {
case CommentTabState.UNRESOLVED:
this._handleOnlyUnresolved();
+ // input is null because it's not rendered yet.
+ focusTo = '#unresolvedRadio';
break;
case CommentTabState.DRAFTS:
this._handleOnlyDrafts();
+ focusTo = '#draftsRadio';
break;
case CommentTabState.SHOW_ALL:
this._handleAllComments();
+ focusTo = '#allRadio';
break;
default:
assertNever(newValue, 'Unsupported preferred state');
}
+ const selector = focusTo;
+ window.setTimeout(() => {
+ const input = this.shadowRoot?.querySelector<HTMLInputElement>(selector);
+ input?.focus();
+ }, 0);
}
}
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
index 8b1ba25..f6bd04e 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
@@ -71,6 +71,9 @@
padding-left: 8px;
margin-right: 16px;
}
+ .partypopper{
+ margin-right: var(--spacing-s);
+ }
</style>
<template is="dom-if" if="[[!hideToggleButtons]]">
<div class="header">
@@ -79,7 +82,7 @@
<paper-toggle-button
id="unresolvedToggle"
checked="{{!unresolvedOnly}}"
- on-tap="_onTapUnresolvedToggle"
+ on-click="_onTapUnresolvedToggle"
>All comments</paper-toggle-button
>
</div>
@@ -89,7 +92,7 @@
<paper-toggle-button
id="draftToggle"
checked="{{_draftsOnly}}"
- on-tap="_onTapUnresolvedToggle"
+ on-click="_onTapUnresolvedToggle"
>Comments with drafts</paper-toggle-button
>
</div>
@@ -125,7 +128,7 @@
on-click="_handleAllComments"
checked="[[_showAllComments(_draftsOnly, unresolvedOnly)]]"
/>
- <label for="all">
+ <label for="allRadio">
All ([[_countAllThreads(threads)]])
</label>
</template>
@@ -139,7 +142,7 @@
<div>
<span>
<template is="dom-if" if="[[_showPartyPopper(threads)]]">
- <span> \🎉 </span>
+ <span class="partypopper">\🎉</span>
</template>
[[_computeEmptyThreadsMessage(threads, _displayedThreads,
unresolvedOnly)]]
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
deleted file mode 100644
index d52da80..0000000
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
+++ /dev/null
@@ -1,146 +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 '../../shared/gr-dialog/gr-dialog';
-import '../../shared/gr-shell-command/gr-shell-command';
-import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-upload-help-dialog_html';
-import {customElement, property} from '@polymer/decorators';
-import {RevisionInfo} from '../../../types/common';
-import {appContext} from '../../../services/app-context';
-
-const COMMIT_COMMAND = 'git add . && git commit --amend --no-edit';
-const PUSH_COMMAND_PREFIX = 'git push origin HEAD:refs/for/';
-
-// Command names correspond to download plugin definitions.
-const PREFERRED_FETCH_COMMAND_ORDER = ['checkout', 'cherry pick', 'pull'];
-
-@customElement('gr-upload-help-dialog')
-export class GrUploadHelpDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
- static get template() {
- return htmlTemplate;
- }
-
- /**
- * Fired when the user presses the close button.
- *
- * @event close
- */
-
- @property({type: Object})
- revision?: RevisionInfo;
-
- @property({type: String})
- targetBranch?: string;
-
- @property({type: String})
- _commitCommand = COMMIT_COMMAND;
-
- @property({
- type: String,
- computed: '_computeFetchCommand(revision, _preferredDownloadScheme)',
- })
- _fetchCommand?: string;
-
- @property({type: String})
- _preferredDownloadScheme?: string;
-
- @property({type: String, computed: '_computePushCommand(targetBranch)'})
- _pushCommand?: string;
-
- private readonly restApiService = appContext.restApiService;
-
- /** @override */
- attached() {
- super.attached();
- this.restApiService
- .getLoggedIn()
- .then(loggedIn =>
- loggedIn
- ? this.restApiService.getPreferences()
- : Promise.resolve(undefined)
- )
- .then(prefs => {
- if (prefs) {
- // TODO(TS): The download_command pref was deleted in change 249223.
- // this._preferredDownloadCommand = prefs.download_command;
- this._preferredDownloadScheme = prefs.download_scheme;
- }
- });
- }
-
- _handleCloseTap(e: Event) {
- e.preventDefault();
- e.stopPropagation();
- this.dispatchEvent(
- new CustomEvent('close', {
- composed: true,
- bubbles: false,
- })
- );
- }
-
- _computeFetchCommand(
- revision?: RevisionInfo,
- scheme?: string
- ): string | undefined {
- if (!revision || !revision.fetch) return undefined;
- if (!scheme) {
- const keys = Object.keys(revision.fetch).sort();
- if (keys.length === 0) {
- return undefined;
- }
- scheme = keys[0];
- }
- if (
- !scheme ||
- !revision.fetch[scheme] ||
- !revision.fetch[scheme].commands
- ) {
- return undefined;
- }
-
- const cmds: {[key: string]: string} = {};
- Object.entries(revision.fetch[scheme].commands!).forEach(([key, cmd]) => {
- cmds[key.toLowerCase()] = cmd;
- });
-
- // If no supported command preference is given, look for known commands
- // from the downloads plugin in order of preference.
- for (let i = 0; i < PREFERRED_FETCH_COMMAND_ORDER.length; i++) {
- if (cmds[PREFERRED_FETCH_COMMAND_ORDER[i]]) {
- return cmds[PREFERRED_FETCH_COMMAND_ORDER[i]];
- }
- }
-
- return undefined;
- }
-
- _computePushCommand(targetBranch: string) {
- return PUSH_COMMAND_PREFIX + targetBranch;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-upload-help-dialog': GrUploadHelpDialog;
- }
-}
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts
deleted file mode 100644
index d44cbb0..0000000
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts
+++ /dev/null
@@ -1,69 +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';
-
-export const htmlTemplate = html`
- <style include="shared-styles">
- :host {
- background-color: var(--dialog-background-color);
- display: block;
- }
- .main {
- width: 100%;
- }
- ol {
- margin-left: var(--spacing-xl);
- list-style: decimal;
- }
- p {
- margin-bottom: var(--spacing-m);
- }
- </style>
- <gr-dialog confirm-label="Done" cancel-label="" on-confirm="_handleCloseTap">
- <div class="header" slot="header">How to update this change:</div>
- <div class="main" slot="main">
- <ol>
- <li>
- <p>
- Checkout this change locally and make your desired modifications to
- the files.
- </p>
- <template is="dom-if" if="[[_fetchCommand]]">
- <gr-shell-command command="[[_fetchCommand]]"></gr-shell-command>
- </template>
- </li>
- <li>
- <p>
- Update the local commit with your modifications using the following
- command.
- </p>
- <gr-shell-command command="[[_commitCommand]]"></gr-shell-command>
- <p>
- Leave the "Change-Id:" line of the commit message as is.
- </p>
- </li>
- <li>
- <p>Push the updated commit to Gerrit.</p>
- <gr-shell-command command="[[_pushCommand]]"></gr-shell-command>
- </li>
- <li>
- <p>Refresh this page to view the the update.</p>
- </li>
- </ol>
- </div>
- </gr-dialog>
-`;
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.js b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.js
deleted file mode 100644
index 005b20d..0000000
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_test.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-upload-help-dialog.js';
-
-const basicFixture = fixtureFromElement('gr-upload-help-dialog');
-
-suite('gr-upload-help-dialog tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('constructs push command from branch', () => {
- element.targetBranch = 'foo';
- assert.equal(element._pushCommand, 'git push origin HEAD:refs/for/foo');
-
- element.targetBranch = 'master';
- assert.equal(element._pushCommand,
- 'git push origin HEAD:refs/for/master');
- });
-
- suite('fetch command', () => {
- const testRev = {
- fetch: {
- http: {
- commands: {
- Checkout: 'http checkout',
- Pull: 'http pull',
- },
- },
- ssh: {
- commands: {
- Pull: 'ssh pull',
- },
- },
- },
- };
-
- test('null cases', () => {
- assert.isUndefined(element._computeFetchCommand());
- assert.isUndefined(element._computeFetchCommand({}));
- assert.isUndefined(element._computeFetchCommand({fetch: null}));
- assert.isUndefined(element._computeFetchCommand({fetch: {}}));
- });
-
- test('revision not defined', () => {
- assert.isUndefined(
- element._computeFetchCommand(undefined, ''));
- });
-
- test('insufficiently defined scheme', () => {
- assert.isUndefined(
- element._computeFetchCommand(testRev, 'badscheme'));
-
- const rev = {...testRev};
- rev.fetch = {...testRev.fetch, nocmds: {commands: {}}};
- assert.isUndefined(
- element._computeFetchCommand(rev, 'nocmds'));
-
- rev.fetch.nocmds.commands.unsupported = 'unsupported';
- assert.isUndefined(
- element._computeFetchCommand(rev, 'nocmds'));
- });
-
- test('default scheme and command', () => {
- const cmd = element._computeFetchCommand(testRev, '');
- assert.isTrue(cmd === 'http checkout' || cmd === 'ssh pull');
- });
-
- test('default command', () => {
- assert.strictEqual(
- element._computeFetchCommand(testRev, 'http'),
- 'http checkout');
- assert.strictEqual(
- element._computeFetchCommand(testRev, 'ssh'),
- 'ssh pull');
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index ef2430c..da596fe 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -15,6 +15,8 @@
* limitations under the License.
*/
import {html} from 'lit-html';
+import {classMap} from 'lit-html/directives/class-map';
+import {repeat} from 'lit-html/directives/repeat';
import {
css,
customElement,
@@ -24,25 +26,46 @@
query,
} from 'lit-element';
import {GrLitElement} from '../lit/gr-lit-element';
+import '@polymer/paper-tooltip/paper-tooltip';
import {
+ Action,
Category,
- CheckRun,
Link,
LinkIcon,
RunStatus,
Tag,
} from '../../api/checks';
import {sharedStyles} from '../../styles/shared-styles';
-import {RunResult} from '../../services/checks/checks-model';
import {
- hasCompleted,
+ allActions$,
+ checksPatchsetNumber$,
+ someProvidersAreLoading$,
+ RunResult,
+ CheckRun,
+} from '../../services/checks/checks-model';
+import {
+ allResults,
+ fireActionTriggered,
hasCompletedWithoutResults,
+ hasResultsOf,
iconForCategory,
- isRunning,
+ iconForLink,
+ tooltipForLink,
} from '../../services/checks/checks-util';
-import {assertIsDefined} from '../../utils/common-util';
-import {whenVisible} from '../../utils/dom-util';
+import {
+ assertIsDefined,
+ check,
+ checkRequiredProperty,
+} from '../../utils/common-util';
+import {toggleClass, whenVisible} from '../../utils/dom-util';
import {durationString} from '../../utils/date-util';
+import {charsOnly, pluralize} from '../../utils/string-util';
+import {fireRunSelectionReset, isSelected} from './gr-checks-util';
+import {ChecksTabState} from '../../types/events';
+import {ConfigInfo, PatchSetNumber} from '../../types/common';
+import {latestPatchNum$} from '../../services/change/change-model';
+import {appContext} from '../../services/app-context';
+import {repoConfig$} from '../../services/config/config-model';
@customElement('gr-result-row')
class GrResultRow extends GrLitElement {
@@ -68,12 +91,15 @@
:host([isexpandable]) {
cursor: pointer;
}
+ gr-result-expanded {
+ cursor: default;
+ }
tr {
border-top: 1px solid var(--border-color);
}
- iron-icon.launch {
+ iron-icon.link {
color: var(--link-color);
- margin-right: var(--spacing-s);
+ margin-right: var(--spacing-m);
}
td.iconCol {
padding-left: var(--spacing-l);
@@ -87,6 +113,16 @@
overflow: hidden;
text-overflow: ellipsis;
}
+ .nameCol .attempt {
+ display: inline-block;
+ background-color: var(--tag-gray);
+ border-radius: var(--line-height-normal);
+ height: var(--line-height-normal);
+ width: var(--line-height-normal);
+ text-align: center;
+ vertical-align: top;
+ font-size: var(--font-size-small);
+ }
.summaryCol {
/* Forces this column to get the remaining space that is left over by
the other columns. */
@@ -101,7 +137,7 @@
}
td .summary-cell {
display: flex;
- max-width: calc(100vw - 700px);
+ max-width: calc(100vw - 630px);
}
td .summary-cell .summary {
font-weight: var(--font-weight-bold);
@@ -119,8 +155,28 @@
overflow: hidden;
text-overflow: ellipsis;
}
+ tr:hover {
+ background: var(--hover-background-color);
+ }
+ tr td .summary-cell .links,
+ tr td .summary-cell .actions,
+ tr.collapsed:hover td .summary-cell .links,
+ tr.collapsed:hover td .summary-cell .actions,
+ :host(.dropdown-open) tr td .summary-cell .links,
+ :host(.dropdown-open) tr td .summary-cell .actions {
+ display: inline-block;
+ margin-left: var(--spacing-s);
+ }
+ tr.collapsed td .summary-cell .links,
+ tr.collapsed td .summary-cell .actions {
+ display: none;
+ }
+ tr.collapsed:hover .summary-cell .tags,
+ tr.collapsed:hover .summary-cell .label {
+ display: none;
+ }
td .summary-cell .tags .tag {
- color: var(--deemphasized-text-color);
+ color: var(--primary-text-color);
display: inline-block;
border-radius: 20px;
background-color: var(--tag-background);
@@ -128,13 +184,43 @@
margin-left: var(--spacing-s);
}
td .summary-cell .label {
- color: var(--deemphasized-text-color);
+ color: var(--primary-text-color);
display: inline-block;
border-radius: 20px;
background-color: var(--label-background);
padding: 0 var(--spacing-m);
margin-left: var(--spacing-s);
}
+ .tag.gray {
+ background-color: var(--tag-gray);
+ }
+ .tag.yellow {
+ background-color: var(--tag-yellow);
+ }
+ .tag.pink {
+ background-color: var(--tag-pink);
+ }
+ .tag.purple {
+ background-color: var(--tag-purple);
+ }
+ .tag.cyan {
+ background-color: var(--tag-cyan);
+ }
+ .tag.brown {
+ background-color: var(--tag-brown);
+ }
+ .actions gr-checks-action,
+ .actions gr-dropdown {
+ /* Fitting a 28px button into 20px line-height. */
+ margin: -4px 0;
+ vertical-align: top;
+ }
+ #moreActions iron-icon {
+ color: var(--link-color);
+ }
+ #moreMessage {
+ display: none;
+ }
`,
];
}
@@ -167,16 +253,24 @@
`;
}
return html`
- <tr class="container" @click="${this.toggleExpanded}">
+ <tr
+ class="${classMap({container: true, collapsed: !this.isExpanded})}"
+ @click="${this.toggleExpanded}"
+ >
<td class="iconCol">
<div>${this.renderIcon()}</div>
</td>
<td class="nameCol">
- <div><span>${this.result.checkName}</span></div>
+ <div>
+ <span>${this.result.checkName}</span>
+ <span class="attempt" ?hidden="${this.result.isSingleAttempt}"
+ >${this.result.attempt}</span
+ >
+ </div>
</td>
<td class="summaryCol">
<div class="summary-cell">
- ${(this.result.links?.slice(0, 5) ?? []).map(this.renderLink)}
+ ${(this.result.links?.slice(0, 1) ?? []).map(this.renderLink)}
${this.renderSummary(this.result.summary)}
<div class="message">
${this.isExpanded ? '' : this.result.message}
@@ -184,12 +278,9 @@
<div class="tags">
${(this.result.tags ?? []).map(t => this.renderTag(t))}
</div>
- ${this.renderLabel()}
+ ${this.renderLabel()} ${this.renderLinks()} ${this.renderActions()}
</div>
- <gr-result-expanded
- .result="${this.result}"
- ?hidden="${!this.isExpanded}"
- ></gr-result-expanded>
+ ${this.renderExpanded()}
</td>
<td class="expanderCol">
<div
@@ -214,11 +305,23 @@
`;
}
+ private renderExpanded() {
+ if (!this.isExpanded) return;
+ return html`<gr-result-expanded
+ .result="${this.result}"
+ @click="${this.avoidToggleExpanded}"
+ ></gr-result-expanded>`;
+ }
+
private toggleExpanded() {
if (!this.isExpandable) return;
this.isExpanded = !this.isExpanded;
}
+ private avoidToggleExpanded(e: Event) {
+ e.stopPropagation();
+ }
+
renderSummary(text?: string) {
if (!text) return;
return html`
@@ -228,18 +331,6 @@
`;
}
- renderLink(link: Link) {
- return html`
- <a href="${link.url}" target="_blank">
- <iron-icon
- aria-label="external link to details"
- class="launch"
- icon="gr-icons:launch"
- ></iron-icon>
- </a>
- `;
- }
-
renderIcon() {
if (this.result?.status !== RunStatus.RUNNING) return;
return html`<iron-icon icon="gr-icons:timelapse"></iron-icon>`;
@@ -251,8 +342,79 @@
return html`<div class="label">${label}</div>`;
}
+ renderLinks() {
+ const links = (this.result?.links ?? []).slice(1);
+ if (links.length === 0) return;
+ return html`<div class="links">${links.map(this.renderLink)}</div>`;
+ }
+
+ renderLink(link: Link) {
+ const tooltipText = link.tooltip ?? tooltipForLink(link.icon);
+ return html`<a href="${link.url}" target="_blank"
+ ><iron-icon
+ aria-label="external link to details"
+ class="link"
+ icon="gr-icons:${iconForLink(link.icon)}"
+ ></iron-icon
+ ><paper-tooltip offset="5">${tooltipText}</paper-tooltip></a
+ >`;
+ }
+
+ private renderActions() {
+ const actions = this.result?.actions ?? [];
+ if (actions.length === 0) return;
+ const overflowItems = actions.slice(2).map(action => {
+ return {...action, id: action.name};
+ });
+ return html`<div class="actions">
+ ${this.renderAction(actions[0])} ${this.renderAction(actions[1])}
+ <gr-dropdown
+ id="moreActions"
+ link=""
+ vertical-offset="32"
+ horizontal-align="right"
+ @tap-item="${this.handleAction}"
+ @opened-changed="${(e: CustomEvent) =>
+ toggleClass(this, 'dropdown-open', e.detail.value)}"
+ ?hidden="${overflowItems.length === 0}"
+ .items="${overflowItems}"
+ >
+ <iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
+ </iron-icon>
+ <span id="moreMessage">More</span>
+ </gr-dropdown>
+ </div>`;
+ }
+
+ private handleAction(e: CustomEvent<Action>) {
+ fireActionTriggered(this, e.detail);
+ }
+
+ private renderAction(action?: Action) {
+ if (!action) return;
+ return html`<gr-checks-action .action="${action}"></gr-checks-action>`;
+ }
+
+ renderPrimaryActions() {
+ const primaryActions = (this.result?.actions ?? []).slice(0, 2);
+ if (primaryActions.length === 0) return;
+ return html`
+ <div class="primaryActions">${primaryActions.map(this.renderAction)}</div>
+ `;
+ }
+
+ renderSecondaryActions() {
+ const secondaryActions = (this.result?.actions ?? []).slice(2);
+ if (secondaryActions.length === 0) return;
+ return html`
+ <div class="secondaryActions">
+ ${secondaryActions.map(this.renderAction)}
+ </div>
+ `;
+ }
+
renderTag(tag: Tag) {
- return html`<div class="tag">${tag.name}</div>`;
+ return html`<div class="tag ${tag.color}">${tag.name}</div>`;
}
}
@@ -261,6 +423,9 @@
@property()
result?: RunResult;
+ @property()
+ repoConfig?: ConfigInfo;
+
static get styles() {
return [
sharedStyles,
@@ -272,21 +437,29 @@
];
}
+ constructor() {
+ super();
+ this.subscribe('repoConfig', repoConfig$);
+ }
+
render() {
if (!this.result) return '';
return html`
<gr-endpoint-decorator name="check-result-expanded">
<gr-endpoint-param
name="run"
- value="${this.result}"
+ .value="${this.result}"
></gr-endpoint-param>
<gr-endpoint-param
name="result"
- value="${this.result}"
+ .value="${this.result}"
></gr-endpoint-param>
- <div class="message">
- ${this.result.message}
- </div>
+ <gr-formatted-text
+ no-trailing-margin=""
+ class="message"
+ content="${this.result.message}"
+ config="${this.repoConfig}"
+ ></gr-formatted-text>
</gr-endpoint-decorator>
`;
}
@@ -303,27 +476,130 @@
@property()
runs: CheckRun[] = [];
+ @property()
+ actions: Action[] = [];
+
+ @property()
+ tabState?: ChecksTabState;
+
+ @property()
+ someProvidersAreLoading = false;
+
+ @property()
+ checksPatchsetNumber: PatchSetNumber | undefined = undefined;
+
+ @property()
+ latestPatchsetNumber: PatchSetNumber | undefined = undefined;
+
+ /**
+ * How many runs are selected in the runs panel?
+ * If 0, then the `runs` property contains all the runs there are.
+ * If >0, then it only contains the data of certain selected runs.
+ */
+ @property()
+ selectedRunsCount = 0;
+
+ /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+ @property()
+ selectedAttempts: Map<string, number | undefined> = new Map<
+ string,
+ number | undefined
+ >();
+
+ /**
+ * This is the current state of whether a section is expanded or not. As long
+ * as isSectionExpandedByUser is false this will be computed by a default rule
+ * on every render.
+ */
private isSectionExpanded = new Map<Category | 'SUCCESS', boolean>();
+ /**
+ * Keeps track of whether the user intentionally changed the expansion state.
+ * Once this is true the default rule for showing a section expanded or not
+ * is not applied anymore.
+ */
+ private isSectionExpandedByUser = new Map<Category | 'SUCCESS', boolean>();
+
+ private readonly checksService = appContext.checksService;
+
+ constructor() {
+ super();
+ this.subscribe('actions', allActions$);
+ this.subscribe('checksPatchsetNumber', checksPatchsetNumber$);
+ this.subscribe('latestPatchsetNumber', latestPatchNum$);
+ this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
+ }
+
static get styles() {
return [
sharedStyles,
css`
:host {
display: block;
- padding: var(--spacing-xl);
+ background-color: var(--background-color-secondary);
}
- input#filterInput {
+ .header {
+ display: block;
+ background-color: var(--background-color-primary);
+ padding: var(--spacing-l) var(--spacing-xl) var(--spacing-m)
+ var(--spacing-xl);
+ border-bottom: 1px solid var(--border-color);
+ }
+ .headerTopRow,
+ .headerBottomRow {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-end;
+ }
+ .headerTopRow gr-dropdown-list {
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ padding: 0 var(--spacing-m);
+ }
+ .headerBottomRow {
margin-top: var(--spacing-s);
+ }
+ .headerBottomRow .right {
+ display: flex;
+ align-items: center;
+ }
+ #moreActions iron-icon {
+ color: var(--link-color);
+ }
+ #moreMessage {
+ display: none;
+ }
+ .body {
+ display: block;
+ padding: var(--spacing-s) var(--spacing-xl) var(--spacing-xl)
+ var(--spacing-xl);
+ }
+ .filterDiv {
+ display: flex;
+ margin-top: var(--spacing-s);
+ align-items: center;
+ }
+ .filterDiv input#filterInput {
padding: var(--spacing-s) var(--spacing-m);
min-width: 400px;
}
+ .filterDiv .selection {
+ padding: var(--spacing-s) var(--spacing-m);
+ }
+ .filterDiv iron-icon.filter {
+ color: var(--selected-foreground);
+ }
+ .filterDiv gr-button.reset {
+ margin: calc(0px - var(--spacing-s)) var(--spacing-l);
+ }
.categoryHeader {
margin-top: var(--spacing-l);
margin-left: var(--spacing-l);
- text-transform: capitalize;
cursor: default;
}
+ .categoryHeader .title {
+ text-transform: capitalize;
+ }
.categoryHeader .expandIcon {
width: var(--line-height-h3);
height: var(--line-height-h3);
@@ -345,6 +621,10 @@
.categoryHeader .statusIcon.success {
color: var(--success-foreground);
}
+ .categoryHeader .filtered {
+ color: var(--deemphasized-text-color);
+ }
+ .collapsed .noResultsMessage,
.collapsed table {
display: none;
}
@@ -352,8 +632,14 @@
border-bottom: 1px solid var(--border-color);
padding-bottom: var(--spacing-m);
}
- .noCompleted {
- margin-top: var(--spacing-l);
+ .noResultsMessage {
+ width: 100%;
+ max-width: 1280px;
+ margin-top: var(--spacing-m);
+ background-color: var(--background-color-primary);
+ box-shadow: var(--elevation-level-1);
+ padding: var(--spacing-s)
+ calc(20px + var(--spacing-l) + var(--spacing-m) + var(--spacing-s));
}
table.resultsTable {
width: 100%;
@@ -371,62 +657,193 @@
];
}
+ protected updated(changedProperties: PropertyValues) {
+ super.updated(changedProperties);
+ if (changedProperties.has('tabState') && this.tabState) {
+ const {statusOrCategory, checkName} = this.tabState;
+ if (
+ statusOrCategory &&
+ statusOrCategory !== RunStatus.RUNNING &&
+ statusOrCategory !== RunStatus.RUNNABLE
+ ) {
+ let cat = statusOrCategory.toString().toLowerCase();
+ if (statusOrCategory === RunStatus.COMPLETED) cat = 'success';
+ this.scrollElIntoView(`.categoryHeader .${cat}`);
+ } else if (checkName) {
+ this.scrollElIntoView(`gr-result-row.${charsOnly(checkName)}`);
+ }
+ }
+ }
+
+ private scrollElIntoView(selector: string) {
+ this.updateComplete.then(() => {
+ let el = this.shadowRoot?.querySelector(selector);
+ // <gr-result-row> has display:contents and cannot be scrolled into view
+ // itself. Thus we are preferring to scroll the first child into view.
+ el = el?.shadowRoot?.firstElementChild ?? el;
+ el?.scrollIntoView({block: 'center'});
+ });
+ }
+
render() {
return html`
- <div><h2 class="heading-2">Results</h2></div>
- ${this.renderFilter()} ${this.renderNoCompleted()}
- ${this.renderSection(Category.ERROR)}
- ${this.renderSection(Category.WARNING)}
- ${this.renderSection(Category.INFO)} ${this.renderSection('SUCCESS')}
+ <div class="header">
+ <div class="headerTopRow">
+ <div class="left">
+ <h2 class="heading-2">Results</h2>
+ </div>
+ <div class="middle">
+ <span ?hidden="${!this.someProvidersAreLoading}">Loading...</span>
+ </div>
+ <div class="right">
+ <gr-dropdown-list
+ value="${this.checksPatchsetNumber}"
+ .items="${this.createPatchsetDropdownItems()}"
+ @value-change="${this.onPatchsetSelected}"
+ ></gr-dropdown-list>
+ </div>
+ </div>
+ <div class="headerBottomRow">
+ <div class="left">${this.renderFilter()}</div>
+ <div class="right">${this.renderActions()}</div>
+ </div>
+ </div>
+ <div class="body">
+ ${this.renderSection(Category.ERROR)}
+ ${this.renderSection(Category.WARNING)}
+ ${this.renderSection(Category.INFO)} ${this.renderSection('SUCCESS')}
+ </div>
`;
}
- renderFilter() {
- if (this.runs.length === 0) return;
+ private renderActions() {
+ const overflowItems = this.actions.slice(2).map(action => {
+ return {...action, id: action.name};
+ });
return html`
- <input
- id="filterInput"
- type="text"
- placeholder="Filter results by regular expression"
- @input="${this.onInput}"
- />
+ ${this.renderAction(this.actions[0])}
+ ${this.renderAction(this.actions[1])}
+ <gr-dropdown
+ id="moreActions"
+ link=""
+ vertical-offset="32"
+ horizontal-align="right"
+ @tap-item="${this.handleAction}"
+ ?hidden="${overflowItems.length === 0}"
+ .items="${overflowItems}"
+ >
+ <iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
+ </iron-icon>
+ <span id="moreMessage">More</span>
+ </gr-dropdown>
`;
}
+ private handleAction(e: CustomEvent<Action>) {
+ fireActionTriggered(this, e.detail);
+ }
+
+ private renderAction(action?: Action) {
+ if (!action) return;
+ return html`<gr-checks-action .action="${action}"></gr-checks-action>`;
+ }
+
+ private onPatchsetSelected(e: CustomEvent<{value: string}>) {
+ const patchset = Number(e.detail.value);
+ check(!isNaN(patchset), 'selected patchset must be a number');
+ this.checksService.setPatchset(patchset as PatchSetNumber);
+ }
+
+ private createPatchsetDropdownItems() {
+ if (!this.latestPatchsetNumber) return [];
+ return Array.from(Array(this.latestPatchsetNumber), (_, i) => {
+ assertIsDefined(this.latestPatchsetNumber, 'latestPatchsetNumber');
+ const index = this.latestPatchsetNumber - i;
+ const postfix = index === this.latestPatchsetNumber ? ' (latest)' : '';
+ return {
+ value: `${index}`,
+ text: `Patchset ${index}${postfix}`,
+ };
+ });
+ }
+
+ renderFilter() {
+ const runs = this.runs.filter(run =>
+ isSelected(this.selectedAttempts, run)
+ );
+ if (this.selectedRunsCount === 0 && allResults(runs).length <= 3) {
+ if (this.filterRegExp.source.length > 0) {
+ this.filterRegExp = new RegExp('');
+ }
+ return;
+ }
+ return html`
+ <div class="filterDiv">
+ <input
+ id="filterInput"
+ type="text"
+ placeholder="Filter results by regular expression"
+ @input="${this.onInput}"
+ />
+ <div class="selection">${this.renderSelectionFilter()}</div>
+ </div>
+ `;
+ }
+
+ renderSelectionFilter() {
+ const count = this.selectedRunsCount;
+ if (count === 0) return;
+ return html`
+ <iron-icon class="filter" icon="gr-icons:filter"></iron-icon>
+ <span>Filtered by ${pluralize(count, 'run')}</span>
+ <gr-button link class="reset" @click="${this.handleClick}"
+ >Reset View</gr-button
+ >
+ `;
+ }
+
+ handleClick() {
+ this.filterRegExp = new RegExp('');
+ fireRunSelectionReset(this);
+ }
+
onInput() {
assertIsDefined(this.filterInput, 'filter <input> element');
this.filterRegExp = new RegExp(this.filterInput.value, 'i');
}
- renderNoCompleted() {
- if (this.runs.some(hasCompleted)) return;
- let text = 'No results';
- if (this.runs.some(isRunning)) {
- text = 'Checks are running ...';
- }
- return html`<div class="noCompleted">${text}</div>`;
- }
-
renderSection(category: Category | 'SUCCESS') {
const catString = category.toString().toLowerCase();
- let runs = this.runs;
+ let runs = this.runs.filter(run => isSelected(this.selectedAttempts, run));
if (category === 'SUCCESS') {
- runs = runs
- .filter(hasCompletedWithoutResults)
- .filter(r => this.filterRegExp.test(r.checkName));
+ runs = runs.filter(hasCompletedWithoutResults);
} else {
- runs = runs.filter(r =>
- (r.results ?? []).some(res => res.category === category)
- );
+ runs = runs.filter(r => hasResultsOf(r, category));
}
- if (runs.length === 0) return;
- const expanded = this.isSectionExpanded.get(category) ?? true;
+ const all = runs.reduce(
+ (allResults: RunResult[], run) => [
+ ...allResults,
+ ...this.computeRunResults(category, run),
+ ],
+ []
+ );
+ const filtered = all.filter(
+ result =>
+ this.filterRegExp.test(result.checkName) ||
+ this.filterRegExp.test(result.summary)
+ );
+ let expanded = this.isSectionExpanded.get(category);
+ const expandedByUser = this.isSectionExpandedByUser.get(category) ?? false;
+ if (!expandedByUser || expanded === undefined) {
+ expanded = all.length > 0;
+ this.isSectionExpanded.set(category, expanded);
+ }
const expandedClass = expanded ? 'expanded' : 'collapsed';
- const icon = expanded ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
+ const icon = expanded ? 'gr-icons:expand-less' : 'gr-icons:expand-more';
return html`
<div class="${expandedClass}">
<h3
- class="categoryHeader heading-3"
+ class="categoryHeader ${catString} heading-3"
@click="${() => this.toggleExpanded(category)}"
>
<iron-icon class="expandIcon" icon="${icon}"></iron-icon>
@@ -434,51 +851,87 @@
icon="gr-icons:${iconForCategory(category)}"
class="statusIcon ${catString}"
></iron-icon>
- ${catString}
+ <span class="title">${catString}</span>
+ <span class="count">${this.renderCount(all, filtered)}</span>
</h3>
- <table class="resultsTable">
- <thead>
- <tr class="headerRow">
- <th class="iconCol"></th>
- <th class="nameCol">Run</th>
- <th class="summaryCol">Summary</th>
- <th class="expanderCol"></th>
- </tr>
- </thead>
- <tbody>
- ${runs.map(run =>
- category === 'SUCCESS'
- ? this.renderSuccessfulRun(run)
- : this.renderRun(category, run)
- )}
- </tbody>
- </table>
+ ${this.renderResults(all, filtered)}
</div>
`;
}
+ renderResults(all: RunResult[], filtered: RunResult[]) {
+ if (all.length === 0 && this.selectedRunsCount > 0) {
+ return html`<div class="noResultsMessage">
+ No results for this filtered view
+ </div>`;
+ }
+ if (all.length === 0) {
+ return html`<div class="noResultsMessage">No results</div>`;
+ }
+ if (filtered.length === 0) {
+ return html`<div class="noResultsMessage">
+ No results match the regular expression
+ </div>`;
+ }
+ return html`
+ <table class="resultsTable">
+ <thead>
+ <tr class="headerRow">
+ <th class="iconCol"></th>
+ <th class="nameCol">Run</th>
+ <th class="summaryCol">Summary</th>
+ <th class="expanderCol"></th>
+ </tr>
+ </thead>
+ <tbody>
+ ${repeat(
+ filtered,
+ result => result.internalResultId,
+ result => html`
+ <gr-result-row
+ class="${charsOnly(result.checkName)}"
+ .result="${result}"
+ ></gr-result-row>
+ `
+ )}
+ </tbody>
+ </table>
+ `;
+ }
+
+ renderCount(all: RunResult[], filtered: RunResult[]) {
+ if (this.selectedRunsCount > 0) {
+ return html`<span class="filtered"> - filtered</span>`;
+ }
+ if (all.length === filtered.length) {
+ return html`(${all.length})`;
+ } else {
+ return html`(${filtered.length} of ${all.length})`;
+ }
+ }
+
toggleExpanded(category: Category | 'SUCCESS') {
- const expanded = this.isSectionExpanded.get(category) ?? true;
+ const expanded = this.isSectionExpanded.get(category);
+ assertIsDefined(expanded, 'expanded must have been set in initial render');
this.isSectionExpanded.set(category, !expanded);
+ this.isSectionExpandedByUser.set(category, true);
this.requestUpdate();
}
- renderRun(category: Category, run: CheckRun) {
- return html`${run.results
- ?.filter(result => result.category === category)
- .filter(
- result =>
- this.filterRegExp.test(run.checkName) ||
- this.filterRegExp.test(result.summary)
- )
- .map(
- result =>
- html`<gr-result-row .result="${{...run, ...result}}"></gr-result-row>`
- )}`;
+ computeRunResults(category: Category | 'SUCCESS', run: CheckRun) {
+ if (category === 'SUCCESS') return [this.computeSuccessfulRunResult(run)];
+ return (
+ run.results
+ ?.filter(result => result.category === category)
+ .map(result => {
+ return {...run, ...result};
+ }) ?? []
+ );
}
- renderSuccessfulRun(run: CheckRun) {
+ computeSuccessfulRunResult(run: CheckRun): RunResult {
const adaptedRun: RunResult = {
+ internalResultId: run.internalRunId + '-0',
category: Category.INFO, // will not be used, but is required
summary: run.statusDescription ?? '',
...run,
@@ -501,7 +954,49 @@
},
];
}
- return html`<gr-result-row .result="${adaptedRun}"></gr-result-row>`;
+ return adaptedRun;
+ }
+}
+
+@customElement('gr-checks-action')
+export class GrChecksAction extends GrLitElement {
+ @property()
+ action!: Action;
+
+ connectedCallback() {
+ super.connectedCallback();
+ checkRequiredProperty(this.action, 'action');
+ }
+
+ static get styles() {
+ return [
+ css`
+ :host {
+ display: inline-block;
+ }
+ gr-button {
+ --padding: var(--spacing-s) var(--spacing-m);
+ }
+ gr-button paper-tooltip {
+ text-transform: none;
+ }
+ `,
+ ];
+ }
+
+ render() {
+ return html`
+ <gr-button link class="action" @click="${this.handleClick}">
+ ${this.action.name}
+ <paper-tooltip ?hidden="${!this.action.tooltip}" offset="5"
+ >${this.action.tooltip}</paper-tooltip
+ >
+ </gr-button>
+ `;
+ }
+
+ handleClick() {
+ fireActionTriggered(this, this.action);
}
}
@@ -510,5 +1005,6 @@
'gr-result-row': GrResultRow;
'gr-result-expanded': GrResultExpanded;
'gr-checks-results': GrChecksResults;
+ 'gr-checks-action': GrChecksAction;
}
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 31f17724..dc09479 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -16,17 +16,20 @@
*/
import {html, nothing} from 'lit-html';
import {classMap} from 'lit-html/directives/class-map';
+import './gr-hovercard-run';
import {
css,
customElement,
internalProperty,
property,
+ PropertyValues,
query,
} from 'lit-element';
import {GrLitElement} from '../lit/gr-lit-element';
-import {Action, CheckRun, RunStatus} from '../../api/checks';
+import {Action, RunStatus} from '../../api/checks';
import {sharedStyles} from '../../styles/shared-styles';
import {
+ AttemptDetail,
compareByWorstCategory,
fireActionTriggered,
iconForCategory,
@@ -35,38 +38,24 @@
worstCategory,
} from '../../services/checks/checks-util';
import {
+ CheckRun,
allRuns$,
+ fakeActions,
fakeRun0,
fakeRun1,
fakeRun2,
fakeRun3,
- fakeRun4,
+ fakeRun4_1,
+ fakeRun4_2,
+ fakeRun4_3,
+ fakeRun4_4,
updateStateSetResults,
} from '../../services/checks/checks-model';
import {assertIsDefined} from '../../utils/common-util';
import {whenVisible} from '../../utils/dom-util';
-
-export interface RunSelectedEventDetail {
- checkName: string;
-}
-
-export type RunSelectedEvent = CustomEvent<RunSelectedEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'run-selected': RunSelectedEvent;
- }
-}
-
-function fireRunSelected(target: EventTarget, checkName: string) {
- target.dispatchEvent(
- new CustomEvent('run-selected', {
- detail: {checkName},
- composed: true,
- bubbles: true,
- })
- );
-}
+import {fireAttemptSelected, fireRunSelected} from './gr-checks-util';
+import {ChecksTabState} from '../../types/events';
+import {charsOnly} from '../../utils/string-util';
@customElement('gr-checks-run')
export class GrChecksRun extends GrLitElement {
@@ -95,6 +84,16 @@
.name {
font-weight: var(--font-weight-bold);
}
+ .attempt {
+ display: inline-block;
+ background-color: var(--tag-gray);
+ border-radius: var(--line-height-normal);
+ height: var(--line-height-normal);
+ width: var(--line-height-normal);
+ text-align: center;
+ vertical-align: top;
+ font-size: var(--font-size-small);
+ }
.chip.error {
border-left: var(--thick-border) solid var(--error-foreground);
}
@@ -130,21 +129,14 @@
}
/* Additional 'div' for increased specificity. */
div.chip.selected {
- border: 1px solid var(--selected-foreground);
+ border: 1px solid var(--selected-background);
background-color: var(--selected-background);
padding-left: calc(var(--spacing-m) + var(--thick-border) - 1px);
}
- div.chip.deselected {
- border: 1px solid var(--gray-foreground);
- background-color: transparent;
- padding-left: calc(var(--spacing-m) + var(--thick-border) - 1px);
- }
- div.chip.selected iron-icon {
+ div.chip.selected .name,
+ div.chip.selected iron-icon.filter {
color: var(--selected-foreground);
}
- div.chip.deselected iron-icon {
- color: var(--gray-foreground);
- }
.chip.selected gr-button.action,
.chip.deselected gr-button.action {
display: none;
@@ -157,6 +149,23 @@
that would not have been a nice click target. */
margin: calc(0px - var(--spacing-xs));
}
+ .attemptDetails {
+ padding-bottom: var(--spacing-s);
+ }
+ .attemptDetail {
+ /* This is thick-border (6) + spacing-m (8) + icon (20) + padding. */
+ padding-left: 39px;
+ padding-top: var(--spacing-s);
+ }
+ .attemptDetail input {
+ width: 14px;
+ height: 14px;
+ /* The next 3 are for placing in the middle of 20px line-height. */
+ vertical-align: top;
+ position: relative;
+ top: 3px;
+ margin-right: var(--spacing-s);
+ }
`,
];
}
@@ -171,6 +180,9 @@
selected = false;
@property()
+ selectedAttempt?: number;
+
+ @property()
deselected = false;
@property()
@@ -185,10 +197,25 @@
);
}
+ protected updated(changedProperties: PropertyValues) {
+ super.updated(changedProperties);
+
+ // For some reason the browser does not pick up the correct `checked` state
+ // that is set in renderAttempt(). So we have to set it programmatically
+ // here.
+ const selectedAttempt = this.selectedAttempt ?? this.run.attempt;
+ const inputToBeSelected = this.shadowRoot?.querySelector(
+ `.attemptDetails input#attempt-${selectedAttempt}`
+ ) as HTMLInputElement | undefined;
+ if (inputToBeSelected) {
+ inputToBeSelected.checked = true;
+ }
+ }
+
render() {
if (!this.shouldRender) return html`<div class="chip">Loading ...</div>`;
- const icon = this.selected ? 'filter' : iconForRun(this.run);
+ const icon = iconForRun(this.run);
const classes = {
chip: true,
[icon]: true,
@@ -199,10 +226,15 @@
return html`
<div @click="${this.handleChipClick}" class="${classMap(classes)}">
+ <gr-hovercard-run .run="${this.run}"></gr-hovercard-run>
<div class="left">
+ ${this.renderFilterIcon()}
<iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
${this.renderAdditionalIcon()}
<span class="name">${this.run.checkName}</span>
+ <span class="attempt" ?hidden="${this.run.isSingleAttempt}"
+ >${this.run.attempt}</span
+ >
</div>
<div class="right">
${action
@@ -215,6 +247,49 @@
: ''}
</div>
</div>
+ <div
+ class="attemptDetails"
+ ?hidden="${this.run.isSingleAttempt || !this.selected}"
+ >
+ ${this.run.attemptDetails.map(a => this.renderAttempt(a))}
+ </div>
+ `;
+ }
+
+ isSelected(detail: AttemptDetail) {
+ // this.selectedAttempt may be undefined, then choose the latest attempt,
+ // which is what this.run has.
+ const selectedAttempt = this.selectedAttempt ?? this.run.attempt;
+ return detail.attempt === selectedAttempt;
+ }
+
+ renderAttempt(detail: AttemptDetail) {
+ const checkNameId = charsOnly(this.run.checkName).toLowerCase();
+ const id = `attempt-${detail.attempt}`;
+ const icon = detail.icon;
+ return html`<div class="attemptDetail">
+ <input
+ type="radio"
+ id="${id}"
+ name="${`${checkNameId}-attempt-choice`}"
+ ?checked="${this.isSelected(detail)}"
+ @change="${() => this.handleAttemptChange(detail)}"
+ />
+ <iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
+ <label for="${id}">Attempt ${detail.attempt}</label>
+ </div>`;
+ }
+
+ handleAttemptChange(detail: AttemptDetail) {
+ if (!this.isSelected(detail)) {
+ fireAttemptSelected(this, this.run.checkName, detail.attempt);
+ }
+ }
+
+ renderFilterIcon() {
+ if (!this.selected) return;
+ return html`
+ <iron-icon class="filter" icon="gr-icons:filter"></iron-icon>
`;
}
@@ -259,6 +334,16 @@
@property()
selectedRuns: string[] = [];
+ /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+ @property()
+ selectedAttempts: Map<string, number | undefined> = new Map<
+ string,
+ number | undefined
+ >();
+
+ @property()
+ tabState?: ChecksTabState;
+
private isSectionExpanded = new Map<RunStatus, boolean>();
constructor() {
@@ -272,7 +357,8 @@
css`
:host {
display: block;
- padding: var(--spacing-xl);
+ padding: var(--spacing-l) var(--spacing-xl) var(--spacing-xl)
+ var(--spacing-xl);
}
.expandIcon {
width: var(--line-height-h3);
@@ -294,7 +380,7 @@
padding-bottom: var(--spacing-m);
}
input#filterInput {
- margin-top: var(--spacing-s);
+ margin-top: var(--spacing-m);
padding: var(--spacing-s) var(--spacing-m);
width: 100%;
}
@@ -315,6 +401,23 @@
];
}
+ protected updated(changedProperties: PropertyValues) {
+ super.updated(changedProperties);
+ if (changedProperties.has('tabState') && this.tabState) {
+ const {statusOrCategory} = this.tabState;
+ if (
+ statusOrCategory === RunStatus.RUNNING ||
+ statusOrCategory === RunStatus.RUNNABLE
+ ) {
+ this.updateComplete.then(() => {
+ const s = statusOrCategory.toString().toLowerCase();
+ const el = this.shadowRoot?.querySelector(`.${s} .sectionHeader`);
+ el?.scrollIntoView({block: 'center'});
+ });
+ }
+ }
+ }
+
render() {
return html`
<h2 class="heading-2">Runs</h2>
@@ -322,6 +425,7 @@
id="filterInput"
type="text"
placeholder="Filter runs by regular expression"
+ ?hidden="${!this.showFilter()}"
@input="${this.onInput}"
/>
${this.renderSection(RunStatus.COMPLETED)}
@@ -330,19 +434,25 @@
<div class="testing">
<div>Toggle fake runs by clicking buttons:</div>
<gr-button link @click="${this.none}">none</gr-button>
- <gr-button link @click="${() => this.toggle('f0', fakeRun0)}"
+ <gr-button
+ link
+ @click="${() => this.toggle('f0', [fakeRun0], fakeActions)}"
>0</gr-button
>
- <gr-button link @click="${() => this.toggle('f1', fakeRun1)}"
+ <gr-button link @click="${() => this.toggle('f1', [fakeRun1])}"
>1</gr-button
>
- <gr-button link @click="${() => this.toggle('f2', fakeRun2)}"
+ <gr-button link @click="${() => this.toggle('f2', [fakeRun2])}"
>2</gr-button
>
- <gr-button link @click="${() => this.toggle('f3', fakeRun3)}"
+ <gr-button link @click="${() => this.toggle('f3', [fakeRun3])}"
>3</gr-button
>
- <gr-button link @click="${() => this.toggle('f4', fakeRun4)}"
+ <gr-button
+ link
+ @click="${() => {
+ this.toggle('f4', [fakeRun4_1, fakeRun4_2, fakeRun4_3, fakeRun4_4]);
+ }}"
>4</gr-button
>
<gr-button link @click="${this.all}">all</gr-button>
@@ -356,7 +466,7 @@
}
none() {
- updateStateSetResults('f0', []);
+ updateStateSetResults('f0', [], []);
updateStateSetResults('f1', []);
updateStateSetResults('f2', []);
updateStateSetResults('f3', []);
@@ -364,27 +474,33 @@
}
all() {
- updateStateSetResults('f0', [fakeRun0]);
+ updateStateSetResults('f0', [fakeRun0], fakeActions);
updateStateSetResults('f1', [fakeRun1]);
updateStateSetResults('f2', [fakeRun2]);
updateStateSetResults('f3', [fakeRun3]);
- updateStateSetResults('f4', [fakeRun4]);
+ updateStateSetResults('f4', [
+ fakeRun4_1,
+ fakeRun4_2,
+ fakeRun4_3,
+ fakeRun4_4,
+ ]);
}
- toggle(plugin: string, run: CheckRun) {
- const newRuns = this.runs.includes(run) ? [] : [run];
- updateStateSetResults(plugin, newRuns);
+ toggle(plugin: string, runs: CheckRun[], actions: Action[] = []) {
+ const newRuns = this.runs.includes(runs[0]) ? [] : runs;
+ updateStateSetResults(plugin, newRuns, actions);
}
renderSection(status: RunStatus) {
const runs = this.runs
+ .filter(r => r.isLatestAttempt)
.filter(r => r.status === status)
.filter(r => this.filterRegExp.test(r.checkName))
.sort(compareByWorstCategory);
if (runs.length === 0) return;
const expanded = this.isSectionExpanded.get(status) ?? true;
const expandedClass = expanded ? 'expanded' : 'collapsed';
- const icon = expanded ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
+ const icon = expanded ? 'gr-icons:expand-less' : 'gr-icons:expand-more';
return html`
<div class="${status.toLowerCase()} ${expandedClass}">
<div
@@ -394,9 +510,7 @@
<iron-icon class="expandIcon" icon="${icon}"></iron-icon>
<h3 class="heading-3">${status.toLowerCase()}</h3>
</div>
- <div class="sectionRuns">
- ${runs.map(run => this.renderRun(run))}
- </div>
+ <div class="sectionRuns">${runs.map(run => this.renderRun(run))}</div>
</div>
`;
}
@@ -408,14 +522,24 @@
}
renderRun(run: CheckRun) {
- const selected = this.selectedRuns.includes(run.checkName);
- const deselected = !selected && this.selectedRuns.length > 0;
+ const selectedRun = this.selectedRuns.includes(run.checkName);
+ const selectedAttempt = this.selectedAttempts.get(run.checkName);
+ const deselected = !selectedRun && this.selectedRuns.length > 0;
return html`<gr-checks-run
.run="${run}"
- .selected="${selected}"
+ .selected="${selectedRun}"
+ .selectedAttempt="${selectedAttempt}"
.deselected="${deselected}"
></gr-checks-run>`;
}
+
+ showFilter(): boolean {
+ const show = this.runs.length > 10;
+ if (!show && this.filterRegExp.source.length > 0) {
+ this.filterRegExp = new RegExp('');
+ }
+ return show;
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-styles.ts b/polygerrit-ui/app/elements/checks/gr-checks-styles.ts
new file mode 100644
index 0000000..9a1605e
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-checks-styles.ts
@@ -0,0 +1,50 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {css} from 'lit-element';
+
+// Mark the file as a module. Otherwise typescript assumes this is a script
+// and $_documentContainer is a global variable.
+// See: https://www.typescriptlang.org/docs/handbook/modules.html
+export {};
+
+const $_documentContainer = document.createElement('template');
+
+export const checksStyles = css`
+ iron-icon.error {
+ color: var(--error-foreground);
+ }
+ iron-icon.warning {
+ color: var(--warning-foreground);
+ }
+ iron-icon.info-outline {
+ color: var(--info-foreground);
+ }
+ iron-icon.check-circle-outline {
+ color: var(--success-foreground);
+ }
+`;
+
+$_documentContainer.innerHTML = `<dom-module id="gr-checks-styles">
+ <template>
+ <style>
+ ${checksStyles.cssText}
+ </style>
+ </template>
+</dom-module>`;
+
+document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
index c072f2c..beec4c8 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
@@ -23,29 +23,20 @@
PropertyValues,
} from 'lit-element';
import {GrLitElement} from '../lit/gr-lit-element';
-import {Action, CheckResult, CheckRun} from '../../api/checks';
+import {Action} from '../../api/checks';
import {
- allActions$,
+ CheckResult,
+ CheckRun,
allResults$,
allRuns$,
checksPatchsetNumber$,
- someProvidersAreLoading$,
} from '../../services/checks/checks-model';
import './gr-checks-runs';
import './gr-checks-results';
-import {sharedStyles} from '../../styles/shared-styles';
-import {changeNum$, latestPatchNum$} from '../../services/change/change-model';
+import {changeNum$} from '../../services/change/change-model';
import {NumericChangeId, PatchSetNumber} from '../../types/common';
-import {
- ActionTriggeredEvent,
- fireActionTriggered,
-} from '../../services/checks/checks-util';
-import {
- assertIsDefined,
- check,
- checkRequiredProperty,
-} from '../../utils/common-util';
-import {RunSelectedEvent} from './gr-checks-runs';
+import {ActionTriggeredEvent} from '../../services/checks/checks-util';
+import {AttemptSelectedEvent, RunSelectedEvent} from './gr-checks-util';
import {ChecksTabState} from '../../types/events';
import {fireAlert} from '../../utils/event-util';
import {appContext} from '../../services/app-context';
@@ -61,10 +52,9 @@
@property()
runs: CheckRun[] = [];
+ @property()
results: CheckResult[] = [];
- actions: Action[] = [];
-
@property()
tabState?: ChecksTabState;
@@ -72,28 +62,26 @@
checksPatchsetNumber: PatchSetNumber | undefined = undefined;
@property()
- latestPatchsetNumber: PatchSetNumber | undefined = undefined;
-
- @property()
changeNum: NumericChangeId | undefined = undefined;
- @property()
- someProvidersAreLoading = false;
-
@internalProperty()
selectedRuns: string[] = [];
+ /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+ @internalProperty()
+ selectedAttempts: Map<string, number | undefined> = new Map<
+ string,
+ number | undefined
+ >();
+
private readonly checksService = appContext.checksService;
constructor() {
super();
this.subscribe('runs', allRuns$);
- this.subscribe('actions', allActions$);
this.subscribe('results', allResults$);
this.subscribe('checksPatchsetNumber', checksPatchsetNumber$);
- this.subscribe('latestPatchsetNumber', latestPatchNum$);
this.subscribe('changeNum', changeNum$);
- this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
this.addEventListener('action-triggered', (e: ActionTriggeredEvent) =>
this.handleActionTriggered(e.detail.action, e.detail.run)
@@ -101,35 +89,22 @@
}
static get styles() {
- return [
- sharedStyles,
- css`
- :host {
- display: block;
- }
- .header {
- display: flex;
- justify-content: space-between;
- padding: var(--spacing-m) var(--spacing-l);
- border-bottom: 1px solid var(--border-color);
- }
- .action {
- margin-left: var(--spacing-m);
- }
- .container {
- display: flex;
- }
- .runs {
- min-width: 300px;
- min-height: 400px;
- border-right: 1px solid var(--border-color);
- }
- .results {
- background-color: var(--background-color-secondary);
- flex-grow: 1;
- }
- `,
- ];
+ return css`
+ :host {
+ display: block;
+ }
+ .container {
+ display: flex;
+ }
+ .runs {
+ min-width: 300px;
+ min-height: 400px;
+ border-right: 1px solid var(--border-color);
+ }
+ .results {
+ flex-grow: 1;
+ }
+ `;
}
render() {
@@ -139,69 +114,37 @@
this.selectedRuns.includes(r.checkName)
);
return html`
- <div class="header">
- <div class="left">
- <gr-dropdown-list
- value="${this.checksPatchsetNumber}"
- .items="${this.createPatchsetDropdownItems()}"
- @value-change="${this.onPatchsetSelected}"
- ></gr-dropdown-list>
- <span ?hidden="${!this.someProvidersAreLoading}">Loading...</span>
- </div>
- <div class="right">
- ${this.actions.map(this.renderAction)}
- </div>
- </div>
<div class="container">
<gr-checks-runs
class="runs"
.runs="${this.runs}"
.selectedRuns="${this.selectedRuns}"
+ .selectedAttempts="${this.selectedAttempts}"
+ .tabState="${this.tabState}"
@run-selected="${this.handleRunSelected}"
+ @attempt-selected="${this.handleAttemptSelected}"
></gr-checks-runs>
<gr-checks-results
class="results"
+ .tabState="${this.tabState}"
.runs="${filteredRuns}"
+ .selectedRunsCount="${this.selectedRuns.length}"
+ .selectedAttempts="${this.selectedAttempts}"
+ @run-selected="${this.handleRunSelected}"
></gr-checks-results>
</div>
`;
}
- private onPatchsetSelected(e: CustomEvent<{value: string}>) {
- const patchset = Number(e.detail.value);
- check(!isNaN(patchset), 'selected patchset must be a number');
- this.checksService.setPatchset(patchset as PatchSetNumber);
- }
-
- private createPatchsetDropdownItems() {
- if (!this.latestPatchsetNumber) return [];
- return Array.from(Array(this.latestPatchsetNumber), (_, i) => {
- assertIsDefined(this.latestPatchsetNumber, 'latestPatchsetNumber');
- const index = this.latestPatchsetNumber - i;
- const postfix = index === this.latestPatchsetNumber ? ' (latest)' : '';
- return {
- value: `${index}`,
- text: `Patchset ${index}${postfix}`,
- };
- });
- }
-
protected updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
if (changedProperties.has('tabState')) {
- const check = this.tabState?.checkName;
- if (check) {
- this.selectedRuns = [check];
+ if (this.tabState) {
+ this.selectedRuns = [];
}
}
}
- renderAction(action: Action) {
- return html`<gr-checks-top-level-action
- .action="${action}"
- ></gr-checks-top-level-action>`;
- }
-
handleActionTriggered(action: Action, run?: CheckRun) {
if (!this.changeNum) return;
if (!this.checksPatchsetNumber) return;
@@ -235,44 +178,36 @@
}
handleRunSelected(e: RunSelectedEvent) {
- this.toggleSelected(e.detail.checkName);
+ if (e.detail.reset) {
+ this.selectedRuns = [];
+ this.selectedAttempts = new Map();
+ return;
+ }
+ if (e.detail.checkName) {
+ this.toggleSelected(e.detail.checkName);
+ }
+ }
+
+ handleAttemptSelected(e: AttemptSelectedEvent) {
+ const {checkName, attempt} = e.detail;
+ this.selectedAttempts.set(checkName, attempt);
+ // Force property update.
+ this.selectedAttempts = new Map(this.selectedAttempts);
}
toggleSelected(checkName: string) {
if (this.selectedRuns.includes(checkName)) {
this.selectedRuns = this.selectedRuns.filter(r => r !== checkName);
+ this.selectedAttempts.set(checkName, undefined);
+ this.selectedAttempts = new Map(this.selectedAttempts);
} else {
this.selectedRuns = [...this.selectedRuns, checkName];
}
}
}
-@customElement('gr-checks-top-level-action')
-export class GrChecksTopLevelAction extends GrLitElement {
- @property()
- action!: Action;
-
- connectedCallback() {
- super.connectedCallback();
- checkRequiredProperty(this.action, 'action');
- }
-
- render() {
- return html`
- <gr-button link class="action" @click="${this.handleClick}"
- >${this.action.name}</gr-button
- >
- `;
- }
-
- handleClick() {
- fireActionTriggered(this, this.action);
- }
-}
-
declare global {
interface HTMLElementTagNameMap {
'gr-checks-tab': GrChecksTab;
- 'gr-checks-top-level-action': GrChecksTopLevelAction;
}
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util.ts b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
new file mode 100644
index 0000000..9a68e5b
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
@@ -0,0 +1,87 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {CheckRun} from '../../services/checks/checks-model';
+
+export interface AttemptSelectedEventDetail {
+ checkName: string;
+ attempt: number | undefined;
+}
+
+export type AttemptSelectedEvent = CustomEvent<AttemptSelectedEventDetail>;
+
+declare global {
+ interface HTMLElementEventMap {
+ 'attempt-selected': AttemptSelectedEvent;
+ }
+}
+
+export function fireAttemptSelected(
+ target: EventTarget,
+ checkName: string,
+ attempt: number | undefined
+) {
+ target.dispatchEvent(
+ new CustomEvent('attempt-selected', {
+ detail: {checkName, attempt},
+ composed: true,
+ bubbles: true,
+ })
+ );
+}
+
+export interface RunSelectedEventDetail {
+ reset: boolean;
+ checkName?: string;
+}
+
+export type RunSelectedEvent = CustomEvent<RunSelectedEventDetail>;
+
+declare global {
+ interface HTMLElementEventMap {
+ 'run-selected': RunSelectedEvent;
+ }
+}
+
+export function fireRunSelected(target: EventTarget, checkName: string) {
+ target.dispatchEvent(
+ new CustomEvent('run-selected', {
+ detail: {reset: false, checkName},
+ composed: true,
+ bubbles: true,
+ })
+ );
+}
+
+export function fireRunSelectionReset(target: EventTarget) {
+ target.dispatchEvent(
+ new CustomEvent('run-selected', {
+ detail: {reset: true},
+ composed: true,
+ bubbles: true,
+ })
+ );
+}
+
+export function isSelected(
+ selectedAttempts: Map<string, number | undefined>,
+ run: CheckRun
+) {
+ const selected = selectedAttempts.get(run.checkName);
+ return (
+ (selected === undefined && run.isLatestAttempt) || selected === run.attempt
+ );
+}
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
new file mode 100644
index 0000000..5ebd05c
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
@@ -0,0 +1,48 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import './gr-checks-styles';
+import {hovercardBehaviorMixin} from '../shared/gr-hovercard/gr-hovercard-behavior';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {htmlTemplate} from './gr-hovercard-run_html';
+import {customElement, property} from '@polymer/decorators';
+import {CheckRun} from '../../services/checks/checks-model';
+import {iconForRun} from '../../services/checks/checks-util';
+import {fromNow} from '../../utils/date-util';
+
+@customElement('gr-hovercard-run')
+export class GrHovercardRun extends hovercardBehaviorMixin(PolymerElement) {
+ static get template() {
+ return htmlTemplate;
+ }
+
+ @property({type: Object})
+ run?: CheckRun;
+
+ computeIcon(run: CheckRun) {
+ return iconForRun(run);
+ }
+
+ computeDuration(date: Date) {
+ return date ? fromNow(date) : '';
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-hovercard-run': GrHovercardRun;
+ }
+}
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
new file mode 100644
index 0000000..cb7e464
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
@@ -0,0 +1,95 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {html} from '@polymer/polymer/lib/utils/html-tag';
+
+export const htmlTemplate = html`
+ <style include="gr-checks-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
+ <style include="gr-hovercard-shared-style">
+ #container {
+ padding: var(--spacing-xl);
+ }
+ h3 iron-icon {
+ position: relative;
+ top: 2px;
+ }
+ .row {
+ margin-top: var(--spacing-s);
+ }
+ .title {
+ color: var(--deemphasized-text-color);
+ margin-right: var(--spacing-s);
+ }
+ iron-icon.launch {
+ color: var(--link-color);
+ }
+ </style>
+ <div id="container" role="tooltip" tabindex="-1">
+ <h3 class="name heading-3">
+ <iron-icon
+ class$="[[computeIcon(run)]]"
+ icon="gr-icons:[[computeIcon(run)]]"
+ ></iron-icon>
+ <span>[[run.checkName]]</span>
+ </h3>
+ <div hidden$="[[!run.checkDescription]]" class="row">
+ <span class="title">Description</span>
+ <span>[[run.checkDescription]]</span>
+ </div>
+ <div hidden$="[[!run.checkLink]]" class="row">
+ <span class="title">Documentation</span>
+ <a href="[[run.checkLink]]" target="_blank">
+ <iron-icon
+ aria-label="external link to check documentation"
+ class="launch"
+ icon="gr-icons:launch"
+ ></iron-icon>
+ </a>
+ </div>
+ <div hidden$="[[!run.statusDescription]]" class="row">
+ <span class="title">Status</span>
+ <span>[[run.statusDescription]]</span>
+ </div>
+ <div hidden$="[[!run.statusLink]]" class="row">
+ <span class="title">Status Link</span>
+ <a href="[[run.statusLink]]" target="_blank">
+ <iron-icon
+ aria-label="external link to check status"
+ class="launch"
+ icon="gr-icons:launch"
+ ></iron-icon>
+ </a>
+ </div>
+ <div hidden$="[[!run.attempt]]" class="row">
+ <span class="title">Attempt</span>
+ <span>[[run.attempt]]</span>
+ </div>
+ <div hidden$="[[!run.scheduledTimestamp]]" class="row">
+ <span class="title">Scheduled</span>
+ <span>[[computeDuration(run.scheduledTimestamp)]]</span>
+ </div>
+ <div hidden$="[[!run.startedTimestamp]]" class="row">
+ <span class="title">Started</span>
+ <span>[[computeDuration(run.startedTimestamp)]]</span>
+ </div>
+ <div hidden$="[[!run.finishedTimestamp]]" class="row">
+ <span class="title">Finished</span>
+ <span>[[computeDuration(run.finishedTimestamp)]]</span>
+ </div>
+ </div>
+`;
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js b/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js
new file mode 100644
index 0000000..9c77654
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js
@@ -0,0 +1,41 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../test/common-test-setup-karma.js';
+import './gr-hovercard-run.js';
+import {html} from '@polymer/polymer/lib/utils/html-tag.js';
+
+const basicFixture = fixtureFromTemplate(html`
+<gr-hovercard-run class="hovered"></gr-hovercard-run>
+`);
+
+suite('gr-hovercard-run tests', () => {
+ let element;
+
+ setup(async () => {
+ element = basicFixture.instantiate();
+ await flush();
+ });
+
+ teardown(() => {
+ element.hide({});
+ });
+
+ test('hovercard is shown', () => {
+ });
+});
+
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
index 0361b9a..198f1d9 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-dropdown/gr-dropdown';
import '../../../styles/shared-styles';
import '../../shared/gr-avatar/gr-avatar';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-dropdown_html';
import {getUserName} from '../../../utils/display-name-util';
@@ -37,9 +35,7 @@
}
@customElement('gr-account-dropdown')
-export class GrAccountDropdown extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountDropdown extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -68,10 +64,10 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
- this._handleLocationChange();
- this.listen(window, 'location-change', '_handleLocationChange');
+ connectedCallback() {
+ super.connectedCallback();
+ this.handleLocationChange();
+ window.addEventListener('location-change', this.handleLocationChange);
this.restApiService.getConfig().then(cfg => {
this.config = cfg;
@@ -85,9 +81,9 @@
}
/** @override */
- detached() {
- super.detached();
- this.unlisten(window, 'location-change', '_handleLocationChange');
+ disconnectedCallback() {
+ window.removeEventListener('location-change', this.handleLocationChange);
+ super.disconnectedCallback();
}
_getLinks(switchAccountUrl: string, path: string) {
@@ -119,10 +115,10 @@
fireEvent(this, 'show-keyboard-shortcuts');
}
- _handleLocationChange() {
+ private readonly handleLocationChange = () => {
this._path =
window.location.pathname + window.location.search + window.location.hash;
- }
+ };
_interpolateUrl(url: string, replacements: {[key: string]: string}) {
return url.replace(
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.js b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.js
index dc5d1b4..d2d27b7 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.js
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.js
@@ -17,7 +17,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-account-dropdown.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-account-dropdown');
@@ -25,7 +24,6 @@
let element;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
index b28b13e..63b5bc8 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../../shared/gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-error-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -29,9 +27,7 @@
}
@customElement('gr-error-dialog')
-export class GrErrorDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrErrorDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.js b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
similarity index 63%
rename from polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.js
rename to polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
index ea8f7c5..fa57a23 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.js
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
@@ -15,21 +15,25 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-error-dialog.js';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import '../../../test/common-test-setup-karma';
+import {queryAndAssert} from '../../../test/test-utils';
+import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
+import {GrErrorDialog} from './gr-error-dialog';
const basicFixture = fixtureFromElement('gr-error-dialog');
suite('gr-error-dialog tests', () => {
- let element;
+ let element: GrErrorDialog;
setup(() => {
element = basicFixture.instantiate();
});
test('dismiss tap fires event', done => {
- element.addEventListener('dismiss', () => { done(); });
- MockInteractions.tap(element.$.dialog.$.confirm);
+ element.addEventListener('dismiss', () => done());
+ MockInteractions.tap(
+ (queryAndAssert(element, '#dialog') as GrDialog).$.confirm
+ );
});
});
-
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
index 4a86005..4985c1b 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
@@ -19,8 +19,6 @@
import '../gr-error-dialog/gr-error-dialog';
import '../../shared/gr-alert/gr-alert';
import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-error-manager_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -32,13 +30,16 @@
import {GrAlert} from '../../shared/gr-alert/gr-alert';
import {ErrorType, FixIronA11yAnnouncer} from '../../../types/types';
import {AccountId} from '../../../types/common';
-import {EventType} from '../../../utils/event-util';
import {
+ EventType,
NetworkErrorEvent,
ServerErrorEvent,
- ShowAlertEvent,
+ ShowAlertEventDetail,
+ ShowErrorEvent,
} from '../../../types/events';
import {windowLocationReload} from '../../../utils/dom-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {fireIronAnnounce} from '../../../utils/event-util';
const HIDE_ALERT_TIMEOUT_MS = 5000;
const CHECK_SIGN_IN_INTERVAL_MS = 60 * 1000;
@@ -74,12 +75,8 @@
};
}
-const DEBOUNCER_CHECK_LOGGED_IN = 'checkLoggedIn';
-
@customElement('gr-error-manager')
-export class GrErrorManager extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrErrorManager extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -119,16 +116,18 @@
private readonly restApiService = appContext.restApiService;
+ private checkLoggedInTask?: DelayedTask;
+
/** @override */
- attached() {
- super.attached();
- this.listen(document, EventType.SERVER_ERROR, '_handleServerError');
- this.listen(document, EventType.NETWORK_ERROR, '_handleNetworkError');
- this.listen(document, EventType.SHOW_ALERT, '_handleShowAlert');
- this.listen(document, 'hide-alert', '_hideAlert');
- this.listen(document, 'show-error', '_handleShowErrorDialog');
- this.listen(document, 'visibilitychange', '_handleVisibilityChange');
- this.listen(document, 'show-auth-required', '_handleAuthRequired');
+ connectedCallback() {
+ super.connectedCallback();
+ document.addEventListener(EventType.SERVER_ERROR, this.handleServerError);
+ document.addEventListener(EventType.NETWORK_ERROR, this.handleNetworkError);
+ document.addEventListener(EventType.SHOW_ALERT, this.handleShowAlert);
+ document.addEventListener('hide-alert', this.hideAlert);
+ document.addEventListener('show-error', this.handleShowErrorDialog);
+ document.addEventListener('visibilitychange', this.handleVisibilityChange);
+ document.addEventListener('show-auth-required', this.handleAuthRequired);
this._authErrorHandlerDeregistrationHook = this.eventEmitter.on(
'auth-error',
@@ -141,33 +140,42 @@
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
this._clearHideAlertHandle();
- this.unlisten(document, EventType.SERVER_ERROR, '_handleServerError');
- this.unlisten(document, EventType.NETWORK_ERROR, '_handleNetworkError');
- this.unlisten(document, EventType.SHOW_ALERT, '_handleShowAlert');
- this.unlisten(document, 'hide-alert', '_hideAlert');
- this.unlisten(document, 'show-error', '_handleShowErrorDialog');
- this.unlisten(document, 'visibilitychange', '_handleVisibilityChange');
- this.unlisten(document, 'show-auth-required', '_handleAuthRequired');
- this.cancelDebouncer(DEBOUNCER_CHECK_LOGGED_IN);
+ document.removeEventListener(
+ EventType.SERVER_ERROR,
+ this.handleServerError
+ );
+ document.removeEventListener(
+ EventType.NETWORK_ERROR,
+ this.handleNetworkError
+ );
+ document.removeEventListener(EventType.SHOW_ALERT, this.handleShowAlert);
+ document.removeEventListener('hide-alert', this.hideAlert);
+ document.removeEventListener('show-error', this.handleShowErrorDialog);
+ document.removeEventListener(
+ 'visibilitychange',
+ this.handleVisibilityChange
+ );
+ document.removeEventListener('show-auth-required', this.handleAuthRequired);
+ this.checkLoggedInTask?.cancel();
if (this._authErrorHandlerDeregistrationHook) {
this._authErrorHandlerDeregistrationHook();
}
+ super.disconnectedCallback();
}
_shouldSuppressError(msg: string) {
return msg.includes(TOO_MANY_FILES);
}
- _handleAuthRequired() {
+ private readonly handleAuthRequired = () => {
this._showAuthErrorAlert(
'Log in is required to perform that action.',
'Log in.'
);
- }
+ };
_handleAuthError(msg: string, action: string) {
this.$.noInteractionOverlay.open().then(() => {
@@ -175,7 +183,7 @@
});
}
- _handleServerError(e: ServerErrorEvent) {
+ private readonly handleServerError = (e: ServerErrorEvent) => {
const {request, response} = e.detail;
response.text().then(errorText => {
const url = request && (request.anonymizedUrl || request.url);
@@ -187,7 +195,7 @@
) {
// if not authed previously, this is trying to access auth required APIs
// show auth required alert
- this._handleAuthRequired();
+ this.handleAuthRequired();
} else if (
response.status === 403 &&
this._authService.isAuthed &&
@@ -223,7 +231,7 @@
}
console.info(`server error: ${errorText}`);
});
- }
+ };
_showNotFoundMessageWithTip({
status,
@@ -283,7 +291,7 @@
return err;
}
- _handleShowAlert(e: ShowAlertEvent) {
+ private readonly handleShowAlert = (e: CustomEvent<ShowAlertEventDetail>) => {
this._showAlert(
e.detail.message,
e.detail.action,
@@ -292,12 +300,12 @@
undefined,
e.detail.showDismiss
);
- }
+ };
- _handleNetworkError(e: NetworkErrorEvent) {
+ private readonly handleNetworkError = (e: NetworkErrorEvent) => {
this._showAlert('Server unavailable');
console.error(e.detail.error.message);
- }
+ };
// TODO(dhruvsr): allow less priority alerts to override high priority alerts
// In some use cases we may want generic alerts to show along/over errors
@@ -316,27 +324,27 @@
if (this._alertElement) {
// check priority before hiding
if (!this._canOverride(type, this._alertElement.type)) return;
- this._hideAlert();
+ this.hideAlert();
}
this._clearHideAlertHandle();
if (dismissOnNavigation) {
// Persist alert until navigation.
- this.listen(document, 'location-change', '_hideAlert');
+ document.addEventListener('location-change', this.hideAlert);
} else {
- this._hideAlertHandle = this.async(
- this._hideAlert,
+ this._hideAlertHandle = window.setTimeout(
+ this.hideAlert,
HIDE_ALERT_TIMEOUT_MS
);
}
const el = this._createToastAlert(showDismiss);
el.show(text, actionText, actionCallback);
this._alertElement = el;
- this.fire('iron-announce', {text: `Alert: ${text}`}, {bubbles: true});
+ fireIronAnnounce(this, `Alert: ${text}`);
this.reporting.reportInteraction('show-alert', {text});
}
- _hideAlert() {
+ private readonly hideAlert = () => {
if (!this._alertElement) {
return;
}
@@ -345,12 +353,12 @@
this._alertElement = null;
// Remove listener for page navigation, if it exists.
- this.unlisten(document, 'location-change', '_hideAlert');
- }
+ document.removeEventListener('location-change', this.hideAlert);
+ };
_clearHideAlertHandle() {
if (this._hideAlertHandle !== null) {
- this.cancelAsync(this._hideAlertHandle);
+ window.clearTimeout(this._hideAlertHandle);
this._hideAlertHandle = null;
}
}
@@ -367,12 +375,12 @@
this._alertElement.show(errorText, actionText, () =>
this._createLoginPopup()
);
- this.fire('iron-announce', {text: errorText}, {bubbles: true});
+ fireIronAnnounce(this, errorText);
this.reporting.reportInteraction('show-auth-error', {text: errorText});
this._refreshingCredentials = true;
this._requestCheckLoggedIn();
if (!document.hidden) {
- this._handleVisibilityChange();
+ this.handleVisibilityChange();
}
}
@@ -383,7 +391,7 @@
return el;
}
- _handleVisibilityChange() {
+ private readonly handleVisibilityChange = () => {
// Ignore when the page is transitioning to hidden (or hidden is undefined).
if (document.hidden !== false) return;
@@ -404,12 +412,12 @@
// - user switched account
this._checkSignedIn();
}
- }
+ };
_requestCheckLoggedIn() {
- this.debounce(
- DEBOUNCER_CHECK_LOGGED_IN,
- this._checkSignedIn,
+ this.checkLoggedInTask = debounce(
+ this.checkLoggedInTask,
+ () => this._checkSignedIn(),
CHECK_SIGN_IN_INTERVAL_MS
);
}
@@ -444,7 +452,7 @@
return;
}
- this._handleCredentialRefreshed();
+ this.handleCredentialRefreshed();
}
});
}
@@ -469,13 +477,13 @@
'_blank',
options.join(',')
);
- this.listen(window, 'focus', '_handleWindowFocus');
+ window.addEventListener('focus', this.handleWindowFocus);
}
- _handleCredentialRefreshed() {
- this.unlisten(window, 'focus', '_handleWindowFocus');
+ handleCredentialRefreshed() {
+ window.removeEventListener('focus', this.handleWindowFocus);
this._refreshingCredentials = false;
- this._hideAlert();
+ this.hideAlert();
this._showAlert('Credentials refreshed.');
this.$.noInteractionOverlay.close();
@@ -483,13 +491,13 @@
this._authService.clearCache();
}
- _handleWindowFocus() {
- this.flushDebouncer(DEBOUNCER_CHECK_LOGGED_IN);
- }
+ private readonly handleWindowFocus = () => {
+ this.checkLoggedInTask?.flush();
+ };
- _handleShowErrorDialog(e: CustomEvent) {
+ private readonly handleShowErrorDialog = (e: ShowErrorEvent) => {
this._showErrorDialog(e.detail.message);
- }
+ };
_handleDismissErrorDialog() {
this.$.errorOverlay.close();
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
index 092daa2..91f119e 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
@@ -21,6 +21,7 @@
import {__testOnly_ErrorType} from './gr-error-manager.js';
import {stubRestApi} from '../../../test/test-utils.js';
import {appContext} from '../../../services/app-context.js';
+import {createPreferences} from '../../../test/test-data-generators.js';
const basicFixture = fixtureFromElement('gr-error-manager');
@@ -40,6 +41,8 @@
.returns(Promise.resolve({ok: true, status: 204}));
getLoggedInStub = stubRestApi('getLoggedIn')
.callsFake(() => appContext.authService.authCheck());
+ stubRestApi('getPreferences').returns(Promise.resolve(
+ createPreferences()));
element = basicFixture.instantiate();
element._authService.clearCache();
toastSpy = sinon.spy(element, '_createToastAlert');
@@ -297,8 +300,8 @@
// now fake authed
fetchStub.returns(Promise.resolve({status: 204}));
- element._handleWindowFocus();
- element.flushDebouncer('checkLoggedIn');
+ element.handleWindowFocus();
+ element.checkLoggedInTask.flush();
await flush();
assert.isTrue(refreshStub.called);
assert.isTrue(hideToastSpy.called);
@@ -443,14 +446,14 @@
'_checkSignedIn');
sinon.stub(Date, 'now').returns(999999);
element._lastCredentialCheck = 0;
- element._handleVisibilityChange();
+ element.handleVisibilityChange();
// Since there is no known account, it should not test credentials.
assert.isFalse(refreshStub.called);
assert.equal(element._lastCredentialCheck, 0);
element.knownAccountId = 123;
- element._handleVisibilityChange();
+ element.handleVisibilityChange();
// Should test credentials, since there is a known account.
assert.isTrue(refreshStub.called);
@@ -463,7 +466,7 @@
.returns(accountPromise);
const requestCheckStub = sinon.stub(element, '_requestCheckLoggedIn');
const handleRefreshStub = sinon.stub(element,
- '_handleCredentialRefreshed');
+ 'handleCredentialRefreshed');
const reloadStub = sinon.stub(element, '_reloadPage');
element.knownAccountId = 1234;
@@ -480,7 +483,7 @@
test('_showAlert hides existing alerts', () => {
element._alertElement = element._createToastAlert();
- const hideStub = sinon.stub(element, '_hideAlert');
+ const hideStub = sinon.stub(element, 'hideAlert');
element._showAlert();
assert.isTrue(hideStub.calledOnce);
});
@@ -522,7 +525,7 @@
element,
'_requestCheckLoggedIn');
const handleRefreshStub = sinon.stub(element,
- '_handleCredentialRefreshed');
+ 'handleCredentialRefreshed');
const reloadStub = sinon.stub(element, '_reloadPage');
element.knownAccountId = 4321; // Different from 1234
@@ -557,7 +560,7 @@
element,
'_requestCheckLoggedIn');
const handleRefreshStub = sinon.stub(element,
- '_handleCredentialRefreshed');
+ 'handleCredentialRefreshed');
const reloadStub = sinon.stub(element, '_reloadPage');
element._refreshingCredentials = true;
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts
index 875cde8..dd023cb 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display_test.ts
@@ -15,9 +15,9 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-key-binding-display.js';
-import {GrKeyBindingDisplay} from './gr-key-binding-display.js';
+import '../../../test/common-test-setup-karma';
+import './gr-key-binding-display';
+import {GrKeyBindingDisplay} from './gr-key-binding-display';
const basicFixture = fixtureFromElement('gr-key-binding-display');
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index 4bd90ea..0ec9b39 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -17,8 +17,6 @@
import '../../shared/gr-button/gr-button';
import '../gr-key-binding-display/gr-key-binding-display';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-keyboard-shortcuts-dialog_html';
import {
@@ -42,7 +40,7 @@
@customElement('gr-keyboard-shortcuts-dialog')
export class GrKeyboardShortcutsDialog extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
+ PolymerElement
) {
static get template() {
return htmlTemplate;
@@ -76,19 +74,19 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.addKeyboardShortcutDirectoryListener(
this.keyboardShortcutDirectoryListener
);
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
this.removeKeyboardShortcutDirectoryListener(
this.keyboardShortcutDirectoryListener
);
+ super.disconnectedCallback();
}
_handleCloseTap(e: MouseEvent) {
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.js b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.js
deleted file mode 100644
index f76041e..0000000
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-keyboard-shortcuts-dialog.js';
-import {ShortcutSection} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
-
-const basicFixture = fixtureFromElement('gr-keyboard-shortcuts-dialog');
-
-suite('gr-keyboard-shortcuts-dialog tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- function update(directory) {
- element._onDirectoryUpdated(directory);
- flush();
- }
-
- suite('_left and _right contents', () => {
- test('empty dialog', () => {
- assert.strictEqual(element._left.length, 0);
- assert.strictEqual(element._right.length, 0);
- });
-
- test('everywhere goes on left', () => {
- update(new Map([
- [ShortcutSection.EVERYWHERE, ['everywhere shortcuts']],
- ]));
- assert.deepEqual(
- element._left,
- [
- {
- section: ShortcutSection.EVERYWHERE,
- shortcuts: ['everywhere shortcuts'],
- },
- ]);
- assert.strictEqual(element._right.length, 0);
- });
-
- test('navigation goes on left', () => {
- update(new Map([
- [ShortcutSection.NAVIGATION, ['navigation shortcuts']],
- ]));
- assert.deepEqual(
- element._left,
- [
- {
- section: ShortcutSection.NAVIGATION,
- shortcuts: ['navigation shortcuts'],
- },
- ]);
- assert.strictEqual(element._right.length, 0);
- });
-
- test('actions go on right', () => {
- update(new Map([
- [ShortcutSection.ACTIONS, ['actions shortcuts']],
- ]));
- assert.deepEqual(
- element._right,
- [
- {
- section: ShortcutSection.ACTIONS,
- shortcuts: ['actions shortcuts'],
- },
- ]);
- assert.strictEqual(element._left.length, 0);
- });
-
- test('reply dialog goes on right', () => {
- update(new Map([
- [ShortcutSection.REPLY_DIALOG, ['reply dialog shortcuts']],
- ]));
- assert.deepEqual(
- element._right,
- [
- {
- section: ShortcutSection.REPLY_DIALOG,
- shortcuts: ['reply dialog shortcuts'],
- },
- ]);
- assert.strictEqual(element._left.length, 0);
- });
-
- test('file list goes on right', () => {
- update(new Map([
- [ShortcutSection.FILE_LIST, ['file list shortcuts']],
- ]));
- assert.deepEqual(
- element._right,
- [
- {
- section: ShortcutSection.FILE_LIST,
- shortcuts: ['file list shortcuts'],
- },
- ]);
- assert.strictEqual(element._left.length, 0);
- });
-
- test('diffs go on right', () => {
- update(new Map([
- [ShortcutSection.DIFFS, ['diffs shortcuts']],
- ]));
- assert.deepEqual(
- element._right,
- [
- {
- section: ShortcutSection.DIFFS,
- shortcuts: ['diffs shortcuts'],
- },
- ]);
- assert.strictEqual(element._left.length, 0);
- });
-
- test('multiple sections on each side', () => {
- update(new Map([
- [ShortcutSection.ACTIONS, ['actions shortcuts']],
- [ShortcutSection.DIFFS, ['diffs shortcuts']],
- [ShortcutSection.EVERYWHERE, ['everywhere shortcuts']],
- [ShortcutSection.NAVIGATION, ['navigation shortcuts']],
- ]));
- assert.deepEqual(
- element._left,
- [
- {
- section: ShortcutSection.EVERYWHERE,
- shortcuts: ['everywhere shortcuts'],
- },
- {
- section: ShortcutSection.NAVIGATION,
- shortcuts: ['navigation shortcuts'],
- },
- ]);
- assert.deepEqual(
- element._right,
- [
- {
- section: ShortcutSection.ACTIONS,
- shortcuts: ['actions shortcuts'],
- },
- {
- section: ShortcutSection.DIFFS,
- shortcuts: ['diffs shortcuts'],
- },
- ]);
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.ts
new file mode 100644
index 0000000..2c76704
--- /dev/null
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_test.ts
@@ -0,0 +1,156 @@
+/**
+ * @license
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import {GrKeyboardShortcutsDialog} from './gr-keyboard-shortcuts-dialog';
+import {
+ SectionView,
+ ShortcutSection,
+} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
+
+const basicFixture = fixtureFromElement('gr-keyboard-shortcuts-dialog');
+
+suite('gr-keyboard-shortcuts-dialog tests', () => {
+ let element: GrKeyboardShortcutsDialog;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+
+ function update(directory: Map<ShortcutSection, SectionView>) {
+ element._onDirectoryUpdated(directory);
+ flush();
+ }
+
+ suite('_left and _right contents', () => {
+ test('empty dialog', () => {
+ assert.isEmpty(element._left);
+ assert.isEmpty(element._right);
+ });
+
+ test('everywhere goes on left', () => {
+ const sectionView = [{binding: [], text: 'everywhere shortcuts'}];
+ update(new Map([[ShortcutSection.EVERYWHERE, sectionView]]));
+ assert.deepEqual(element._left, [
+ {
+ section: ShortcutSection.EVERYWHERE,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._right);
+ });
+
+ test('navigation goes on left', () => {
+ const sectionView = [{binding: [], text: 'navigation shortcuts'}];
+ update(new Map([[ShortcutSection.NAVIGATION, sectionView]]));
+ assert.deepEqual(element._left, [
+ {
+ section: ShortcutSection.NAVIGATION,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._right);
+ });
+
+ test('actions go on right', () => {
+ const sectionView = [{binding: [], text: 'actions shortcuts'}];
+ update(new Map([[ShortcutSection.ACTIONS, sectionView]]));
+ assert.deepEqual(element._right, [
+ {
+ section: ShortcutSection.ACTIONS,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._left);
+ });
+
+ test('reply dialog goes on right', () => {
+ const sectionView = [{binding: [], text: 'reply dialog shortcuts'}];
+ update(new Map([[ShortcutSection.REPLY_DIALOG, sectionView]]));
+ assert.deepEqual(element._right, [
+ {
+ section: ShortcutSection.REPLY_DIALOG,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._left);
+ });
+
+ test('file list goes on right', () => {
+ const sectionView = [{binding: [], text: 'file list shortcuts'}];
+ update(new Map([[ShortcutSection.FILE_LIST, sectionView]]));
+ assert.deepEqual(element._right, [
+ {
+ section: ShortcutSection.FILE_LIST,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._left);
+ });
+
+ test('diffs go on right', () => {
+ const sectionView = [{binding: [], text: 'diffs shortcuts'}];
+ update(new Map([[ShortcutSection.DIFFS, sectionView]]));
+ assert.deepEqual(element._right, [
+ {
+ section: ShortcutSection.DIFFS,
+ shortcuts: sectionView,
+ },
+ ]);
+ assert.isEmpty(element._left);
+ });
+
+ test('multiple sections on each side', () => {
+ const actionsSectionView = [{binding: [], text: 'actions shortcuts'}];
+ const diffsSectionView = [{binding: [], text: 'diffs shortcuts'}];
+ const everywhereSectionView = [
+ {binding: [], text: 'everywhere shortcuts'},
+ ];
+ const navigationSectionView = [
+ {binding: [], text: 'navigation shortcuts'},
+ ];
+ update(
+ new Map([
+ [ShortcutSection.ACTIONS, actionsSectionView],
+ [ShortcutSection.DIFFS, diffsSectionView],
+ [ShortcutSection.EVERYWHERE, everywhereSectionView],
+ [ShortcutSection.NAVIGATION, navigationSectionView],
+ ])
+ );
+ assert.deepEqual(element._left, [
+ {
+ section: ShortcutSection.EVERYWHERE,
+ shortcuts: everywhereSectionView,
+ },
+ {
+ section: ShortcutSection.NAVIGATION,
+ shortcuts: navigationSectionView,
+ },
+ ]);
+ assert.deepEqual(element._right, [
+ {
+ section: ShortcutSection.ACTIONS,
+ shortcuts: actionsSectionView,
+ },
+ {
+ section: ShortcutSection.DIFFS,
+ shortcuts: diffsSectionView,
+ },
+ ]);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index bed07a6..816ed87 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-icons/gr-icons';
import '../gr-account-dropdown/gr-account-dropdown';
import '../gr-smart-search/gr-smart-search';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-main-header_html';
import {getBaseUrl, getDocsBaseUrl} from '../../../utils/url-util';
@@ -101,9 +99,7 @@
]);
@customElement('gr-main-header')
-export class GrMainHeader extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrMainHeader extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -165,15 +161,15 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadAccount();
this._loadConfig();
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
+ super.disconnectedCallback();
}
reload() {
@@ -240,10 +236,10 @@
items.forEach(link => {
topMenuLinks[m.name].push(link);
});
- } else {
+ } else if (items.length > 0) {
links.push({
title: m.name,
- links: topMenuLinks[m.name] = items,
+ links: (topMenuLinks[m.name] = items),
});
}
}
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
index cf7d3ae..7f3970f 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
@@ -225,7 +225,7 @@
<iron-icon
id="mobileSearch"
icon="gr-icons:search"
- on-tap="_onMobileSearchTap"
+ on-click="_onMobileSearchTap"
role="button"
aria-label="[[_computeShowHideAriaLabel(mobileSearchHidden)]]"
></iron-icon>
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
index d9c43d6..784b440 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
@@ -35,11 +35,7 @@
setup(() => {
stubRestApi('probePath').returns(Promise.resolve(false));
- stub('gr-main-header', {
- _loadAccount() {
- return Promise.resolve();
- },
- });
+ stub('gr-main-header', '_loadAccount').callsFake(() => Promise.resolve());
element = basicFixture.instantiate();
});
@@ -478,7 +474,7 @@
test('shows feedback icon when URL provided', async () => {
assert.isEmpty(element._feedbackURL);
- assert.isNull(query(element, '.feedbackButton'));
+ assert.isNotOk(query(element, '.feedbackButton'));
const url = 'report_bug_url';
const config: ServerInfo = {
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
index 632ce4c..fa81103 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import {
+ BasePatchSetNum,
BranchName,
ChangeConfigInfo,
ChangeInfo,
@@ -253,7 +254,7 @@
changeNum: NumericChangeId;
project: RepoName;
patchNum?: PatchSetNum;
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
edit?: boolean;
host?: string;
messageHash?: string;
@@ -310,7 +311,7 @@
project: RepoName;
path?: string;
patchNum?: PatchSetNum | null;
- basePatchNum?: PatchSetNum | null;
+ basePatchNum?: BasePatchSetNum | null;
lineNum?: number | string;
leftSide?: boolean;
commentId?: UrlEncodedCommentId;
@@ -435,7 +436,7 @@
mapCommentlinks: uninitializedMapCommentLinks,
- _checkPatchRange(patchNum?: PatchSetNum, basePatchNum?: PatchSetNum) {
+ _checkPatchRange(patchNum?: PatchSetNum, basePatchNum?: BasePatchSetNum) {
if (basePatchNum && !patchNum) {
throw new Error('Cannot use base patch number without patch number.');
}
@@ -591,7 +592,7 @@
getUrlForChange(
change: Pick<ChangeInfo, '_number' | 'project' | 'internalHost'>,
patchNum?: PatchSetNum,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
isEdit?: boolean,
messageHash?: string
) {
@@ -635,7 +636,7 @@
navigateToChange(
change: Pick<ChangeInfo, '_number' | 'project' | 'internalHost'>,
patchNum?: PatchSetNum,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
isEdit?: boolean,
redirect?: boolean
) {
@@ -652,7 +653,7 @@
change: ChangeInfo | ParsedChangeInfo,
filePath: string,
patchNum?: PatchSetNum,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
lineNum?: number
) {
return this.getUrlForDiffById(
@@ -686,7 +687,7 @@
project: RepoName,
filePath: string,
patchNum?: PatchSetNum,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
lineNum?: number,
leftSide?: boolean
) {
@@ -751,7 +752,7 @@
change: ChangeInfo | ParsedChangeInfo,
filePath: string,
patchNum?: PatchSetNum,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
lineNum?: number
) {
this._navigate(
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index 676ef7b..4aefc16 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {
page,
@@ -23,7 +21,6 @@
PageNextCallback,
} from '../../../utils/page-wrapper-utils';
import {htmlTemplate} from './gr-router_html';
-import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {
DashboardSection,
GeneratedWebLink,
@@ -50,6 +47,7 @@
import {customElement, property} from '@polymer/decorators';
import {assertNever} from '../../../utils/common-util';
import {
+ BasePatchSetNum,
DashboardId,
GroupId,
NumericChangeId,
@@ -68,6 +66,14 @@
import {firePageError} from '../../../utils/event-util';
import {addQuotesWhen} from '../../../utils/string-util';
import {windowLocationReload} from '../../../utils/dom-util';
+import {
+ encodeURL,
+ getBaseUrl,
+ toPath,
+ toPathname,
+ toSearchParams,
+} from '../../../utils/url-util';
+import {Execution, LifeCycle, Timing} from '../../../constants/reporting';
const RoutePattern = {
ROOT: '/',
@@ -261,7 +267,7 @@
// Setup listeners outside of the router component initialization.
(function () {
window.addEventListener('WebComponentsReady', () => {
- appContext.reportingService.timeEnd('WebComponentsReady');
+ appContext.reportingService.timeEnd(Timing.WEB_COMPONENTS_READY);
});
})();
@@ -282,13 +288,11 @@
interface PatchRangeParams {
patchNum?: PatchSetNum | null;
- basePatchNum?: PatchSetNum | null;
+ basePatchNum?: BasePatchSetNum | null;
}
@customElement('gr-router')
-export class GrRouter extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRouter extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -762,20 +766,23 @@
/** Page.js middleware that try parse the querystring into queryMap. */
_queryStringMiddleware(ctx: PageContext, next: PageNextCallback) {
- let queryMap: Map<string, string> | URLSearchParams = new Map<
- string,
- string
- >();
+ (ctx as PageContextWithQueryMap).queryMap = this.createQueryMap(ctx);
+ next();
+ }
+
+ private createQueryMap(ctx: PageContext) {
if (ctx.querystring) {
// https://caniuse.com/#search=URLSearchParams
if (window.URLSearchParams) {
- queryMap = new URLSearchParams(ctx.querystring);
+ return new URLSearchParams(ctx.querystring);
} else {
- queryMap = new Map(this._parseQueryString(ctx.querystring));
+ this.reporting.reportExecution(Execution.REACHABLE_CODE, {
+ id: 'noURLSearchParams',
+ });
+ return new Map(this._parseQueryString(ctx.querystring));
}
}
- (ctx as PageContextWithQueryMap).queryMap = queryMap;
- next();
+ return new Map<string, string>();
}
/**
@@ -806,13 +813,13 @@
pattern,
(ctx, next) => this._loadUserMiddleware(ctx, next),
(ctx, next) => this._queryStringMiddleware(ctx, next),
- data => {
+ ctx => {
this.reporting.locationChanged(handlerName);
const promise = authRedirect
- ? this._redirectIfNotLoggedIn(data)
+ ? this._redirectIfNotLoggedIn(ctx)
: Promise.resolve();
promise.then(() => {
- this[handlerName](data as PageContextWithQueryMap);
+ this[handlerName](ctx as PageContextWithQueryMap);
});
}
);
@@ -846,6 +853,23 @@
next();
});
+ // Remove the tracking param 'usp' (User Source Parameter) from the URL,
+ // just to have users look at cleaner URLs.
+ page((ctx, next) => {
+ if (window.URLSearchParams) {
+ const pathname = toPathname(ctx.canonicalPath);
+ const searchParams = toSearchParams(ctx.canonicalPath);
+ if (searchParams.has('usp')) {
+ const usp = searchParams.get('usp');
+ this.reporting.reportLifeCycle(LifeCycle.USER_REFERRED_FROM, {usp});
+ searchParams.delete('usp');
+ this._redirect(toPath(pathname, searchParams));
+ return;
+ }
+ }
+ next();
+ });
+
// Middleware
page((ctx, next) => {
document.body.scrollTop = 0;
@@ -860,7 +884,7 @@
// Fire asynchronously so that the URL is changed by the time the event
// is processed.
- this.async(() => {
+ setTimeout(() => {
const detail: LocationChangeEventDetail = {
hash: window.location.hash,
pathname: window.location.pathname,
@@ -1545,7 +1569,7 @@
const params: GenerateUrlChangeViewParameters = {
project: ctx.params[0] as RepoName,
changeNum,
- basePatchNum: convertToPatchSetNum(ctx.params[4]),
+ basePatchNum: convertToPatchSetNum(ctx.params[4]) as BasePatchSetNum,
patchNum: convertToPatchSetNum(ctx.params[6]),
view: GerritView.CHANGE,
queryMap: ctx.queryMap,
@@ -1576,7 +1600,7 @@
const params: GenerateUrlDiffViewParameters = {
project: ctx.params[0] as RepoName,
changeNum,
- basePatchNum: convertToPatchSetNum(ctx.params[4]),
+ basePatchNum: convertToPatchSetNum(ctx.params[4]) as BasePatchSetNum,
patchNum: convertToPatchSetNum(ctx.params[6]),
path: ctx.params[8],
view: GerritView.DIFF,
@@ -1595,7 +1619,7 @@
// Parameter order is based on the regex group number matched.
const params: GenerateUrlLegacyChangeViewParameters = {
changeNum: Number(ctx.params[0]) as NumericChangeId,
- basePatchNum: convertToPatchSetNum(ctx.params[3]),
+ basePatchNum: convertToPatchSetNum(ctx.params[3]) as BasePatchSetNum,
patchNum: convertToPatchSetNum(ctx.params[5]),
view: GerritView.CHANGE,
querystring: ctx.querystring,
@@ -1612,7 +1636,7 @@
// Parameter order is based on the regex group number matched.
const params: GenerateUrlLegacyDiffViewParameters = {
changeNum: Number(ctx.params[0]) as NumericChangeId,
- basePatchNum: convertToPatchSetNum(ctx.params[2]),
+ basePatchNum: convertToPatchSetNum(ctx.params[2]) as BasePatchSetNum,
patchNum: convertToPatchSetNum(ctx.params[4]),
path: ctx.params[5],
view: GerritView.DIFF,
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
index f7fe091..ad4ebcb 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
@@ -19,10 +19,8 @@
import './gr-router.js';
import {page} from '../../../utils/page-wrapper-utils.js';
import {GerritNav} from '../gr-navigation/gr-navigation.js';
-import {stubBaseUrl} from '../../../test/test-utils.js';
+import {stubBaseUrl, stubRestApi, addListenerForTest} from '../../../test/test-utils.js';
import {_testOnly_RoutePattern} from './gr-router.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-import {addListenerForTest} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-router');
@@ -804,7 +802,6 @@
});
test('redirects to dashboard if logged in', () => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
const data = {
canonicalPath: '/', path: '/', querystring: '', hash: '',
};
@@ -934,7 +931,6 @@
});
test('dashboard while signed in sets params', () => {
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
const data = {canonicalPath: '/dashboard/', params: {0: 'foo'}};
return element._handleDashboardRoute(data, '').then(() => {
assert.isFalse(redirectToLoginStub.called);
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 32e0083..9c63f8b 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -17,8 +17,6 @@
import '../../shared/gr-autocomplete/gr-autocomplete';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-search-bar_html';
import {
@@ -44,6 +42,7 @@
'age:',
'age:1week', // Give an example age
'assignee:',
+ 'attention:',
'author:',
'before:',
'branch:',
@@ -146,9 +145,7 @@
}
@customElement('gr-search-bar')
-export class GrSearchBar extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrSearchBar extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -198,8 +195,8 @@
this.query = (input: string) => this._getSearchSuggestions(input);
}
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.restApiService.getConfig().then((serverConfig?: ServerInfo) => {
const mergeability =
serverConfig &&
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.js b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.js
index e553402..ae7e10c 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.js
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.js
@@ -18,10 +18,9 @@
import '../../../test/common-test-setup-karma.js';
import './gr-search-bar.js';
import '../../../scripts/util.js';
-import {TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
+import {TestKeyboardShortcutBinder, stubRestApi} from '../../../test/test-utils.js';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
import {_testOnly_clearDocsBaseUrlCache} from '../../../utils/url-util.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-search-bar');
@@ -126,7 +125,6 @@
suite('_getSearchSuggestions', () => {
setup(() => {
// Ensure that config.change.mergeability_computation_behavior is not set.
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
index b698732..aa7e2e0 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../gr-search-bar/gr-search-bar';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-smart-search_html';
import {GerritNav} from '../gr-navigation/gr-navigation';
@@ -35,9 +33,7 @@
const ME_EXPRESSION = 'me';
@customElement('gr-smart-search')
-export class GrSmartSearch extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrSmartSearch extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -66,8 +62,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.restApiService.getConfig().then(cfg => {
this._config = cfg;
});
diff --git a/polygerrit-ui/app/elements/custom-dark-theme_test.js b/polygerrit-ui/app/elements/custom-dark-theme_test.js
index d4b05e2..97a2750 100644
--- a/polygerrit-ui/app/elements/custom-dark-theme_test.js
+++ b/polygerrit-ui/app/elements/custom-dark-theme_test.js
@@ -54,10 +54,10 @@
assert.equal(
getComputedStyleValue('--header-background-color', element)
.toLowerCase(),
- '#3b3d3f');
+ '#3c4043');
assert.equal(
getComputedStyleValue('--footer-background-color', element)
.toLowerCase(),
- '#3b3d3f');
+ '#3c4043');
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index e381213..0bf9f1c 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-dialog/gr-dialog';
import '../../shared/gr-overlay/gr-overlay';
import '../gr-diff/gr-diff';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-apply-fix-dialog_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -32,18 +30,21 @@
FixSuggestionInfo,
PatchSetNum,
RobotId,
+ BasePatchSetNum,
} from '../../../types/common';
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
import {isRobot} from '../../../utils/comment-util';
import {OpenFixPreviewEvent} from '../../../types/events';
import {appContext} from '../../../services/app-context';
-import {fireEvent} from '../../../utils/event-util';
+import {fireCloseFixPreview, fireEvent} from '../../../utils/event-util';
import {ParsedChangeInfo} from '../../../types/types';
+import {GrButton} from '../../shared/gr-button/gr-button';
export interface GrApplyFixDialog {
$: {
applyFixOverlay: GrOverlay;
+ nextFix: GrButton;
};
}
@@ -53,9 +54,7 @@
}
@customElement('gr-apply-fix-dialog')
-export class GrApplyFixDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrApplyFixDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -134,8 +133,8 @@
});
}
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.refitOverlay = () => {
// re-center the dialog as content changed
fireEvent(this.$.applyFixOverlay, 'iron-resize');
@@ -143,11 +142,11 @@
this.addEventListener('diff-context-expanded', this.refitOverlay);
}
- detached() {
- super.detached();
+ disconnectedCallback() {
if (this.refitOverlay) {
this.removeEventListener('diff-context-expanded', this.refitOverlay);
}
+ super.disconnectedCallback();
}
_showSelectedFixSuggestion(fixSuggestion: FixSuggestionInfo) {
@@ -171,7 +170,7 @@
}
})
.catch(err => {
- this._close();
+ this._close(false);
throw err;
});
}
@@ -189,7 +188,7 @@
if (e) {
e.stopPropagation();
}
- this._close();
+ this._close(false);
}
addOneTo(_selectedFixIdx: number) {
@@ -228,12 +227,12 @@
return _selectedFixIdx === fixSuggestions.length - 1;
}
- _close() {
+ _close(fixApplied: boolean) {
this._currentFix = undefined;
this._currentPreviews = [];
this._isApplyFixLoading = false;
- fireEvent(this, 'close-fix-preview');
+ fireCloseFixPreview(this, fixApplied);
this.$.applyFixOverlay.close();
}
@@ -280,8 +279,12 @@
.applyFixSuggestion(changeNum, patchNum, this._currentFix.fix_id)
.then(res => {
if (res && res.ok) {
- GerritNav.navigateToChange(change, EditPatchSetNum, patchNum);
- this._close();
+ GerritNav.navigateToChange(
+ change,
+ EditPatchSetNum,
+ patchNum as BasePatchSetNum
+ );
+ this._close(true);
}
this._isApplyFixLoading = false;
});
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js
deleted file mode 100644
index d78961c..0000000
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.js
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * @license
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-apply-fix-dialog.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-apply-fix-dialog');
-
-suite('gr-apply-fix-dialog tests', () => {
- let element;
-
- const ROBOT_COMMENT_WITH_TWO_FIXES = {
- robot_id: 'robot_1',
- fix_suggestions: [{fix_id: 'fix_1'}, {fix_id: 'fix_2'}],
- };
-
- const ROBOT_COMMENT_WITH_ONE_FIX = {
- robot_id: 'robot_1',
- fix_suggestions: [{fix_id: 'fix_1'}],
- };
-
- setup(() => {
- element = basicFixture.instantiate();
- element.changeNum = '1';
- element._patchNum = 2;
- element.change = {
- _number: '1',
- project: 'project',
- revisions: {
- abcd: {_number: 1},
- efgh: {_number: 2},
- },
- current_revision: 'efgh',
- };
- element.prefs = {
- font_size: 12,
- line_length: 100,
- tab_size: 4,
- };
- });
-
- suite('dialog open', () => {
- setup(() => {
- stubRestApi('getRobotCommentFixPreview')
- .returns(Promise.resolve({
- f1: {
- meta_a: {},
- meta_b: {},
- content: [
- {
- ab: ['loqlwkqll'],
- },
- {
- b: ['qwqqsqw'],
- },
- {
- ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'],
- },
- ],
- },
- f2: {
- meta_a: {},
- meta_b: {},
- content: [
- {
- ab: ['eqweqweqwex'],
- },
- {
- b: ['zassdasd'],
- },
- {
- ab: ['zassdasd', 'dasdasda', 'asdasdad'],
- },
- ],
- },
- }));
- sinon.stub(element.$.applyFixOverlay, 'open')
- .returns(Promise.resolve());
- });
-
- test('dialog opens fetch and sets previews', done => {
- element.open({detail: {patchNum: 2,
- comment: ROBOT_COMMENT_WITH_TWO_FIXES}})
- .then(() => {
- assert.equal(element._currentFix.fix_id, 'fix_1');
- assert.equal(element._currentPreviews.length, 2);
- assert.equal(element._robotId, 'robot_1');
- const button = element.shadowRoot.querySelector(
- '#applyFixDialog').shadowRoot.querySelector('#confirm');
- assert.isFalse(button.hasAttribute('disabled'));
- assert.equal(button.getAttribute('title'), '');
- done();
- });
- });
-
- test('tooltip is hidden if apply fix is loading', done => {
- element.open({detail: {patchNum: 2,
- comment: ROBOT_COMMENT_WITH_TWO_FIXES}})
- .then(() => {
- element._isApplyFixLoading = true;
- const button = element.shadowRoot.querySelector(
- '#applyFixDialog').shadowRoot.querySelector('#confirm');
- assert.isTrue(button.hasAttribute('disabled'));
- assert.equal(button.getAttribute('title'), '');
- done();
- });
- });
-
- test('apply fix button is disabled on older patchset', done => {
- element.change = {
- _number: '1',
- project: 'project',
- revisions: {
- abcd: {_number: 1},
- efgh: {_number: 2},
- },
- current_revision: 'abcd',
- };
- element.open({detail: {patchNum: 2,
- comment: ROBOT_COMMENT_WITH_ONE_FIX}})
- .then(() => {
- flush(() => {
- const button = element.shadowRoot.querySelector(
- '#applyFixDialog').shadowRoot.querySelector('#confirm');
- assert.isTrue(button.hasAttribute('disabled'));
- assert.equal(button.getAttribute('title'),
- 'Fix can only be applied to the latest patchset');
- done();
- });
- });
- });
- });
-
- test('next button state updated when suggestions changed', done => {
- stubRestApi('getRobotCommentFixPreview').returns(Promise.resolve({}));
- sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
-
- element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_ONE_FIX}})
- .then(() => assert.isTrue(element.$.nextFix.disabled))
- .then(() =>
- element.open({detail: {patchNum: 2,
- comment: ROBOT_COMMENT_WITH_TWO_FIXES}}))
- .then(() => {
- assert.isFalse(element.$.nextFix.disabled);
- done();
- });
- });
-
- test('preview endpoint throws error should reset dialog', async () => {
- stubRestApi('getRobotCommentFixPreview').returns(
- Promise.reject(new Error('backend error')));
- element.open({detail: {patchNum: 2,
- comment: ROBOT_COMMENT_WITH_TWO_FIXES}});
- await flush();
- assert.equal(element._currentFix, undefined);
- });
-
- test('apply fix button should call apply ' +
- 'and navigate to change view', () => {
- const stub = stubRestApi('applyFixSuggestion').returns(
- Promise.resolve({ok: true}));
- sinon.stub(GerritNav, 'navigateToChange');
- element._currentFix = {fix_id: '123'};
-
- return element._handleApplyFix().then(() => {
- assert.isTrue(stub.calledWithExactly('1', 2, '123'));
- assert.isTrue(GerritNav.navigateToChange.calledWithExactly({
- _number: '1',
- project: 'project',
- revisions: {
- abcd: {_number: 1},
- efgh: {_number: 2},
- },
- current_revision: 'efgh',
- }, 'edit', 2));
-
- // reset gr-apply-fix-dialog and close
- assert.equal(element._currentFix, undefined);
- assert.equal(element._currentPreviews.length, 0);
- });
- });
-
- test('should not navigate to change view if incorect reponse', done => {
- const stub = stubRestApi('applyFixSuggestion').returns(Promise.resolve({}));
- sinon.stub(GerritNav, 'navigateToChange');
- element._currentFix = {fix_id: '123'};
-
- element._handleApplyFix().then(() => {
- assert.isTrue(stub.calledWithExactly('1', 2, '123'));
- assert.isTrue(GerritNav.navigateToChange.notCalled);
-
- assert.equal(element._isApplyFixLoading, false);
- done();
- });
- });
-
- test('select fix forward and back of multiple suggested fixes', done => {
- stubRestApi('getRobotCommentFixPreview')
- .returns(Promise.resolve({
- f1: {
- meta_a: {},
- meta_b: {},
- content: [
- {
- ab: ['loqlwkqll'],
- },
- {
- b: ['qwqqsqw'],
- },
- {
- ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'],
- },
- ],
- },
- f2: {
- meta_a: {},
- meta_b: {},
- content: [
- {
- ab: ['eqweqweqwex'],
- },
- {
- b: ['zassdasd'],
- },
- {
- ab: ['zassdasd', 'dasdasda', 'asdasdad'],
- },
- ],
- },
- }));
- sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
-
- element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_TWO_FIXES}})
- .then(() => {
- element._onNextFixClick();
- assert.equal(element._currentFix.fix_id, 'fix_2');
- element._onPrevFixClick();
- assert.equal(element._currentFix.fix_id, 'fix_1');
- done();
- });
- });
-
- test('server-error should throw for failed apply call', async () => {
- stubRestApi('applyFixSuggestion').returns(
- Promise.reject(new Error('backend error')));
- sinon.stub(GerritNav, 'navigateToChange');
- element._currentFix = {fix_id: '123'};
- let expectedError;
- await element._handleApplyFix().catch(e => {
- expectedError = e;
- });
- assert.isOk(expectedError);
- assert.isFalse(GerritNav.navigateToChange.called);
- });
-});
-
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
new file mode 100644
index 0000000..d3d7615
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
@@ -0,0 +1,376 @@
+/**
+ * @license
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-apply-fix-dialog';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {GrApplyFixDialog} from './gr-apply-fix-dialog';
+import {
+ BasePatchSetNum,
+ EditPatchSetNum,
+ PatchSetNum,
+ RobotId,
+ RobotRunId,
+ Timestamp,
+ UrlEncodedCommentId,
+} from '../../../types/common';
+import {
+ createFixSuggestionInfo,
+ createParsedChange,
+ createRevisions,
+ getCurrentRevision,
+} from '../../../test/test-data-generators';
+import {createDefaultDiffPrefs} from '../../../constants/constants';
+import {DiffInfo} from '../../../types/diff';
+import {UIRobot} from '../../../utils/comment-util';
+import {
+ CloseFixPreviewEventDetail,
+ EventType,
+ OpenFixPreviewEventDetail,
+} from '../../../types/events';
+import {GrButton} from '../../shared/gr-button/gr-button';
+
+const basicFixture = fixtureFromElement('gr-apply-fix-dialog');
+
+suite('gr-apply-fix-dialog tests', () => {
+ let element: GrApplyFixDialog;
+
+ const ROBOT_COMMENT_WITH_TWO_FIXES: UIRobot = {
+ id: '1' as UrlEncodedCommentId,
+ updated: '2018-02-08 18:49:18.000000000' as Timestamp,
+ robot_id: 'robot_1' as RobotId,
+ robot_run_id: 'run_1' as RobotRunId,
+ properties: {},
+ fix_suggestions: [
+ createFixSuggestionInfo('fix_1'),
+ createFixSuggestionInfo('fix_2'),
+ ],
+ };
+
+ const ROBOT_COMMENT_WITH_ONE_FIX: UIRobot = {
+ id: '2' as UrlEncodedCommentId,
+ updated: '2018-02-08 18:49:18.000000000' as Timestamp,
+ robot_id: 'robot_1' as RobotId,
+ robot_run_id: 'run_1' as RobotRunId,
+ properties: {},
+ fix_suggestions: [createFixSuggestionInfo('fix_1')],
+ };
+
+ function getConfirmButton(): GrButton {
+ return queryAndAssert(
+ queryAndAssert(element, '#applyFixDialog'),
+ '#confirm'
+ );
+ }
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ const change = {
+ ...createParsedChange(),
+ revisions: createRevisions(2),
+ current_revision: getCurrentRevision(1),
+ };
+ element.changeNum = change._number;
+ element._patchNum = change.revisions[change.current_revision]._number;
+ element.change = change;
+ element.prefs = {
+ ...createDefaultDiffPrefs(),
+ font_size: 12,
+ line_length: 100,
+ tab_size: 4,
+ };
+ });
+
+ suite('dialog open', () => {
+ setup(() => {
+ const diffInfo1: DiffInfo = {
+ meta_a: {
+ name: 'f1',
+ content_type: 'text',
+ lines: 10,
+ },
+ meta_b: {
+ name: 'f1',
+ content_type: 'text',
+ lines: 12,
+ },
+ content: [
+ {
+ ab: ['loqlwkqll'],
+ },
+ {
+ b: ['qwqqsqw'],
+ },
+ {
+ ab: ['qwqqsqw', 'qweqeqweqeq', 'qweqweq'],
+ },
+ ],
+ change_type: 'MODIFIED',
+ intraline_status: 'OK',
+ };
+
+ const diffInfo2: DiffInfo = {
+ meta_a: {
+ name: 'f2',
+ content_type: 'text',
+ lines: 10,
+ },
+ meta_b: {
+ name: 'f2',
+ content_type: 'text',
+ lines: 12,
+ },
+ content: [
+ {
+ ab: ['eqweqweqwex'],
+ },
+ {
+ b: ['zassdasd'],
+ },
+ {
+ ab: ['zassdasd', 'dasdasda', 'asdasdad'],
+ },
+ ],
+ change_type: 'MODIFIED',
+ intraline_status: 'OK',
+ };
+
+ stubRestApi('getRobotCommentFixPreview').returns(
+ Promise.resolve({
+ f1: diffInfo1,
+ f2: diffInfo2,
+ })
+ );
+ sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
+ });
+
+ test('dialog opens fetch and sets previews', async () => {
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES,
+ },
+ })
+ );
+ assert.equal(element._currentFix!.fix_id, 'fix_1');
+ assert.equal(element._currentPreviews.length, 2);
+ assert.equal(element._robotId, 'robot_1' as RobotId);
+ const button = getConfirmButton();
+ assert.isFalse(button.hasAttribute('disabled'));
+ assert.equal(button.getAttribute('title'), '');
+ });
+
+ test('tooltip is hidden if apply fix is loading', async () => {
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES,
+ },
+ })
+ );
+ element._isApplyFixLoading = true;
+ const button = getConfirmButton();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.equal(button.getAttribute('title'), '');
+ });
+
+ test('apply fix button is disabled on older patchset', async () => {
+ element.change = element.change = {
+ ...createParsedChange(),
+ revisions: createRevisions(2),
+ current_revision: getCurrentRevision(0),
+ };
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_ONE_FIX,
+ },
+ })
+ );
+ await flush();
+ const button = getConfirmButton();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.equal(
+ button.getAttribute('title'),
+ 'Fix can only be applied to the latest patchset'
+ );
+ });
+ });
+
+ test('next button state updated when suggestions changed', async () => {
+ stubRestApi('getRobotCommentFixPreview').returns(Promise.resolve({}));
+ sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
+
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_ONE_FIX,
+ },
+ })
+ );
+ assert.isTrue(element.$.nextFix.disabled);
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES,
+ },
+ })
+ );
+ assert.isFalse(element.$.nextFix.disabled);
+ });
+
+ test('preview endpoint throws error should reset dialog', async () => {
+ stubRestApi('getRobotCommentFixPreview').returns(
+ Promise.reject(new Error('backend error'))
+ );
+ element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES,
+ },
+ })
+ );
+ await flush();
+ assert.equal(element._currentFix, undefined);
+ });
+
+ test('apply fix button should call apply, navigate to change view and fire close', async () => {
+ const applyFixSuggestionStub = stubRestApi('applyFixSuggestion').returns(
+ Promise.resolve(new Response(null, {status: 200}))
+ );
+ const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange');
+ element._currentFix = createFixSuggestionInfo('123');
+
+ const closeFixPreviewEventSpy = sinon.spy();
+ // Element is recreated after each test, removeEventListener isn't required
+ element.addEventListener(
+ EventType.CLOSE_FIX_PREVIEW,
+ closeFixPreviewEventSpy
+ );
+ await element._handleApplyFix(new CustomEvent('confirm'));
+
+ sinon.assert.calledOnceWithExactly(
+ applyFixSuggestionStub,
+ element.change!._number,
+ 2 as PatchSetNum,
+ '123'
+ );
+ sinon.assert.calledWithExactly(
+ navigateToChangeStub,
+ element.change!,
+ EditPatchSetNum,
+ element.change!.revisions[2]._number as BasePatchSetNum
+ );
+
+ sinon.assert.calledOnceWithExactly(
+ closeFixPreviewEventSpy,
+ new CustomEvent<CloseFixPreviewEventDetail>(EventType.CLOSE_FIX_PREVIEW, {
+ detail: {
+ fixApplied: true,
+ },
+ })
+ );
+
+ // reset gr-apply-fix-dialog and close
+ assert.equal(element._currentFix, undefined);
+ assert.equal(element._currentPreviews.length, 0);
+ });
+
+ test('should not navigate to change view if incorect reponse', async () => {
+ const applyFixSuggestionStub = stubRestApi('applyFixSuggestion').returns(
+ Promise.resolve(new Response(null, {status: 500}))
+ );
+ const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange');
+ element._currentFix = createFixSuggestionInfo('fix_123');
+
+ await element._handleApplyFix(new CustomEvent('confirm'));
+ sinon.assert.calledWithExactly(
+ applyFixSuggestionStub,
+ element.change!._number,
+ 2 as PatchSetNum,
+ 'fix_123'
+ );
+ assert.isTrue(navigateToChangeStub.notCalled);
+
+ assert.equal(element._isApplyFixLoading, false);
+ });
+
+ test('select fix forward and back of multiple suggested fixes', async () => {
+ sinon.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
+
+ await element.open(
+ new CustomEvent<OpenFixPreviewEventDetail>(EventType.OPEN_FIX_PREVIEW, {
+ detail: {
+ patchNum: 2 as PatchSetNum,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES,
+ },
+ })
+ );
+ element._onNextFixClick(new CustomEvent('click'));
+ assert.equal(element._currentFix!.fix_id, 'fix_2');
+ element._onPrevFixClick(new CustomEvent('click'));
+ assert.equal(element._currentFix!.fix_id, 'fix_1');
+ });
+
+ test('server-error should throw for failed apply call', async () => {
+ stubRestApi('applyFixSuggestion').returns(
+ Promise.reject(new Error('backend error'))
+ );
+ const navigateToChangeStub = sinon.stub(GerritNav, 'navigateToChange');
+ element._currentFix = createFixSuggestionInfo('fix_123');
+
+ const closeFixPreviewEventSpy = sinon.spy();
+ // Element is recreated after each test, removeEventListener isn't required
+ element.addEventListener(
+ EventType.CLOSE_FIX_PREVIEW,
+ closeFixPreviewEventSpy
+ );
+
+ let expectedError;
+ await element._handleApplyFix(new CustomEvent('click')).catch(e => {
+ expectedError = e;
+ });
+ assert.isOk(expectedError);
+ assert.isFalse(navigateToChangeStub.called);
+ sinon.assert.notCalled(closeFixPreviewEventSpy);
+ });
+
+ test('onCancel fires close with correct parameters', () => {
+ const closeFixPreviewEventSpy = sinon.spy();
+ // Element is recreated after each test, removeEventListener isn't required
+ element.addEventListener(
+ EventType.CLOSE_FIX_PREVIEW,
+ closeFixPreviewEventSpy
+ );
+ element.onCancel(new CustomEvent('cancel'));
+ sinon.assert.calledOnceWithExactly(
+ closeFixPreviewEventSpy,
+ new CustomEvent<CloseFixPreviewEventDetail>(EventType.CLOSE_FIX_PREVIEW, {
+ detail: {
+ fixApplied: false,
+ },
+ })
+ );
+ });
+});
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
index b60a585..b382495 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-comment-api_html';
import {CURRENT} from '../../../utils/patch-set-util';
@@ -51,7 +49,6 @@
import {PatchSetFile, PatchNumOnly, isPatchSetFile} from '../../../types/types';
import {appContext} from '../../../services/app-context';
import {CommentSide, Side} from '../../../constants/constants';
-import {KnownExperimentId} from '../../../services/flags/flags';
import {pluralize} from '../../../utils/string-util';
export type CommentIdToCommentThreadMap = {
@@ -149,12 +146,8 @@
const commentMap: CommentMap = {};
for (const response of responses) {
for (const [path, comments] of Object.entries(response)) {
- if (
- comments.some(c => {
- // If don't care about patch range, we know that the path exists.
- return !patchRange || isInPatchRange(c, patchRange);
- })
- ) {
+ // If don't care about patch range, we know that the path exists.
+ if (comments.some(c => !patchRange || isInPatchRange(c, patchRange))) {
commentMap[path] = true;
}
}
@@ -597,9 +590,7 @@
export const _testOnly_getCommentsForPath =
ChangeComments.prototype.getCommentsForPath;
@customElement('gr-comment-api')
-export class GrCommentApi extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCommentApi extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -609,22 +600,6 @@
private readonly restApiService = appContext.restApiService;
- private readonly flagsService = appContext.flagsService;
-
- private isPortingCommentsExperimentEnabled = false;
-
- /** @override */
- created() {
- super.created();
- }
-
- constructor() {
- super();
- this.isPortingCommentsExperimentEnabled = this.flagsService.isEnabled(
- KnownExperimentId.PORTING_COMMENTS
- );
- }
-
/**
* Load all comments (with drafts and robot comments) for the given change
* number. The returned promise resolves when the comments have loaded, but
@@ -636,12 +611,8 @@
this.restApiService.getDiffComments(changeNum),
this.restApiService.getDiffRobotComments(changeNum),
this.restApiService.getDiffDrafts(changeNum),
- this.isPortingCommentsExperimentEnabled
- ? this.restApiService.getPortedComments(changeNum, revision)
- : Promise.resolve({}),
- this.isPortingCommentsExperimentEnabled
- ? this.restApiService.getPortedDrafts(changeNum, revision)
- : Promise.resolve({}),
+ this.restApiService.getPortedComments(changeNum, revision),
+ this.restApiService.getPortedDrafts(changeNum, revision),
];
return Promise.all(commentsPromise).then(
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
index 94ec78f..fbbe1fb 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
@@ -60,7 +60,6 @@
test('loads logged-in', () => {
const changeNum = 1234;
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
const getCommentsStub = stubRestApi('getDiffComments').returns(
Promise.resolve({
'foo.c': [{id: '123', message: 'foo bar', in_reply_to: '321'}],
diff --git a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
index 6f9705f..f121113 100644
--- a/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-coverage-layer/gr-coverage-layer.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-coverage-layer_html';
import {CoverageRange, CoverageType, DiffLayer} from '../../../types/types';
@@ -35,9 +33,7 @@
]);
@customElement('gr-coverage-layer')
-export class GrCoverageLayer
- extends GestureEventListeners(LegacyElementMixin(PolymerElement))
- implements DiffLayer {
+export class GrCoverageLayer extends PolymerElement implements DiffLayer {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
index de68554..76ebc50 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-hovercard/gr-hovercard';
import '../gr-ranged-comment-layer/gr-ranged-comment-layer';
import './gr-diff-builder-side-by-side';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-builder-element_html';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
@@ -43,7 +41,7 @@
GrRangedCommentLayer,
} from '../gr-ranged-comment-layer/gr-ranged-comment-layer';
import {GrCoverageLayer} from '../gr-coverage-layer/gr-coverage-layer';
-import {DiffViewMode} from '../../../api/diff';
+import {DiffViewMode, RenderPreferences} from '../../../api/diff';
import {Side} from '../../../constants/constants';
import {GrDiffLine, LineNumber} from '../gr-diff/gr-diff-line';
import {GrDiffGroup} from '../gr-diff/gr-diff-group';
@@ -67,9 +65,7 @@
}
@customElement('gr-diff-builder')
-export class GrDiffBuilderElement extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffBuilderElement extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -143,6 +139,9 @@
@property({type: Array})
coverageRanges: CoverageRange[] = [];
+ @property({type: Boolean})
+ useNewImageDiffUi = false;
+
@property({
type: Array,
computed: '_computeLeftCoverageRanges(coverageRanges)',
@@ -164,15 +163,16 @@
_cancelableRenderPromise: CancelablePromise<unknown> | null = null;
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
if (this._builder) {
this._builder.clear();
}
+ super.disconnectedCallback();
}
- get diffElement() {
- return this.queryEffectiveChildren('#diffTable') as HTMLTableElement;
+ get diffElement(): HTMLTableElement {
+ // Not searching in shadowRoot, because the diff table is slotted!
+ return this.querySelector('#diffTable') as HTMLTableElement;
}
_computeLeftCoverageRanges(coverageRanges: CoverageRange[]) {
@@ -183,7 +183,11 @@
return coverageRanges.filter(range => range && range.side === 'right');
}
- render(keyLocations: KeyLocations, prefs: DiffPreferencesInfo) {
+ render(
+ keyLocations: KeyLocations,
+ prefs: DiffPreferencesInfo,
+ renderPrefs?: RenderPreferences
+ ) {
// Setting up annotation layers must happen after plugins are
// installed, and |render| satisfies the requirement, however,
// |attached| doesn't because in the diff view page, the element is
@@ -202,7 +206,7 @@
if (!this.diff) {
throw Error('Cannot render a diff without DiffInfo.');
}
- this._builder = this._getDiffBuilder(this.diff, prefs);
+ this._builder = this._getDiffBuilder(this.diff, prefs, renderPrefs);
this.$.processor.context = prefs.context;
this.$.processor.keyLocations = keyLocations;
@@ -241,6 +245,7 @@
this._createTrailingWhitespaceLayer(),
this._createIntralineLayer(),
this._createTabIndicatorLayer(),
+ this._createSpecialCharacterIndicatorLayer(),
this.$.rangeLayer,
this.$.coverageLayerLeft,
this.$.coverageLayerRight,
@@ -325,7 +330,7 @@
sectionEl.parentNode.removeChild(sectionEl);
}
- this.async(() => fireEvent(this, 'render-content'), 1);
+ setTimeout(() => fireEvent(this, 'render-content'), 1);
}
cancel() {
@@ -344,7 +349,11 @@
throw Error(`Invalid preference value: ${pref}`);
}
- _getDiffBuilder(diff: DiffInfo, prefs: DiffPreferencesInfo): GrDiffBuilder {
+ _getDiffBuilder(
+ diff: DiffInfo,
+ prefs: DiffPreferencesInfo,
+ renderPrefs?: RenderPreferences
+ ): GrDiffBuilder {
if (isNaN(prefs.tab_size) || prefs.tab_size <= 0) {
this._handlePreferenceError('tab size');
}
@@ -367,7 +376,9 @@
localPrefs,
this.diffElement,
this.baseImage,
- this.revisionImage
+ this.revisionImage,
+ renderPrefs,
+ this.useNewImageDiffUi
);
} else if (diff.binary) {
// If the diff is binary, but not an image.
@@ -377,14 +388,16 @@
diff,
localPrefs,
this.diffElement,
- this._layers
+ this._layers,
+ renderPrefs
);
} else if (this.viewMode === DiffViewMode.UNIFIED) {
builder = new GrDiffBuilderUnified(
diff,
localPrefs,
this.diffElement,
- this._layers
+ this._layers,
+ renderPrefs
);
}
if (!builder) {
@@ -476,10 +489,33 @@
};
}
- _createTrailingWhitespaceLayer(): DiffLayer {
- const show = () => {
- return this._showTrailingWhitespace;
+ _createSpecialCharacterIndicatorLayer(): DiffLayer {
+ return {
+ annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
+ // Find and annotate the locations of soft hyphen.
+ const split = line.text.split('\u00AD'); // \u00AD soft hyphen
+ if (!split || split.length < 2) {
+ return;
+ }
+ for (let i = 0, pos = 0; i < split.length - 1; i++) {
+ // Skip forward by the length of the content
+ pos += split[i].length;
+
+ GrAnnotation.annotateElement(
+ contentEl,
+ pos,
+ 1,
+ 'style-scope gr-diff special-char-indicator'
+ );
+
+ pos++;
+ }
+ },
};
+ }
+
+ _createTrailingWhitespaceLayer(): DiffLayer {
+ const show = () => this._showTrailingWhitespace;
return {
annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
index 0ae0e84..7c01a95 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
@@ -843,7 +843,7 @@
},
];
element = basicFixture.instantiate();
- outputEl = element.queryEffectiveChildren('#diffTable');
+ outputEl = element.querySelector('#diffTable');
keyLocations = {left: {}, right: {}};
sinon.stub(element, '_getDiffBuilder').callsFake(() => {
const builder = new GrDiffBuilderSideBySide({content}, prefs, outputEl);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.ts
index 5b3f225..650a9e7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.ts
@@ -19,6 +19,9 @@
import {ImageInfo} from '../../../types/common';
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {GrEndpointParam} from '../../plugins/gr-endpoint-param/gr-endpoint-param';
+import {RenderPreferences} from '../../../api/diff';
+import '../gr-diff-image-viewer/gr-image-viewer';
+import {GrImageViewer} from '../gr-diff-image-viewer/gr-image-viewer';
// MIME types for images we allow showing. Do not include SVG, it can contain
// arbitrary JavaScript.
@@ -30,19 +33,27 @@
prefs: DiffPreferencesInfo,
outputEl: HTMLElement,
private readonly _baseImage: ImageInfo | null,
- private readonly _revisionImage: ImageInfo | null
+ private readonly _revisionImage: ImageInfo | null,
+ renderPrefs?: RenderPreferences,
+ private readonly _useNewImageDiffUi: boolean = false
) {
- super(diff, prefs, outputEl, []);
+ super(diff, prefs, outputEl, [], renderPrefs);
}
public renderDiff() {
const section = this._createElement('tbody', 'image-diff');
- this._emitImagePair(section);
- this._emitImageLabels(section);
+ if (this._useNewImageDiffUi) {
+ this._emitImageViewer(section);
- this._outputEl.appendChild(section);
- this._outputEl.appendChild(this._createEndpoint());
+ this._outputEl.appendChild(section);
+ } else {
+ this._emitImagePair(section);
+ this._emitImageLabels(section);
+
+ this._outputEl.appendChild(section);
+ this._outputEl.appendChild(this._createEndpoint());
+ }
}
private _createEndpoint() {
@@ -76,6 +87,27 @@
return endpointParam;
}
+ private _emitImageViewer(section: HTMLElement) {
+ const tr = this._createElement('tr');
+ const td = this._createElement('td');
+ // TODO(hermannloose): Support blame for image diffs, see above.
+ td.setAttribute('colspan', '4');
+ const imageViewer = this._createElement('gr-image-viewer') as GrImageViewer;
+
+ imageViewer.baseUrl = this._getImageSrc(this._baseImage);
+ imageViewer.revisionUrl = this._getImageSrc(this._revisionImage);
+
+ td.appendChild(imageViewer);
+ tr.appendChild(td);
+ section.appendChild(tr);
+ }
+
+ private _getImageSrc(image: ImageInfo | null): string {
+ return image && IMAGE_MIME_PATTERN.test(image.type)
+ ? `data:${image.type};base64,${image.body}`
+ : '';
+ }
+
private _emitImagePair(section: HTMLElement) {
const tr = this._createElement('tr');
@@ -96,18 +128,19 @@
section: HTMLElement
) {
const td = this._createElement('td', className);
- if (image && IMAGE_MIME_PATTERN.test(image.type)) {
+ const src = this._getImageSrc(image);
+ if (image && src) {
const imageEl = this._createElement('img') as HTMLImageElement;
imageEl.onload = () => {
image._height = imageEl.naturalHeight;
image._width = imageEl.naturalWidth;
this._updateImageLabel(section, className, image);
};
- imageEl.setAttribute('src', `data:${image.type};base64, ${image.body}`);
imageEl.addEventListener('error', (e: Event) => {
imageEl.remove();
td.textContent = '[Image failed to load] ' + e.type;
});
+ imageEl.setAttribute('src', src);
td.appendChild(imageEl);
}
return td;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
index 2025732..f44e006 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
@@ -21,15 +21,17 @@
import {GrDiffLine, LineNumber} from '../gr-diff/gr-diff-line';
import {DiffViewMode, Side} from '../../../constants/constants';
import {DiffLayer} from '../../../types/types';
+import {RenderPreferences} from '../../../api/diff';
export class GrDiffBuilderSideBySide extends GrDiffBuilder {
constructor(
diff: DiffInfo,
prefs: DiffPreferencesInfo,
outputEl: HTMLElement,
- readonly layers: DiffLayer[] = []
+ readonly layers: DiffLayer[] = [],
+ renderPrefs?: RenderPreferences
) {
- super(diff, prefs, outputEl, layers);
+ super(diff, prefs, outputEl, layers, renderPrefs);
}
_getMoveControlsConfig() {
@@ -81,12 +83,12 @@
colgroup.appendChild(col);
// Add left-side line number.
- col = document.createElement('col');
+ col = this._createElement('col', 'left');
col.setAttribute('width', width.toString());
colgroup.appendChild(col);
// Add left-side content.
- colgroup.appendChild(document.createElement('col'));
+ colgroup.appendChild(this._createElement('col', 'left'));
// Add right-side line number.
col = document.createElement('col');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
index 1bf3d69..e927fdf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
@@ -20,15 +20,17 @@
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {DiffViewMode, Side} from '../../../constants/constants';
import {DiffLayer} from '../../../types/types';
+import {RenderPreferences} from '../../../api/diff';
export class GrDiffBuilderUnified extends GrDiffBuilder {
constructor(
diff: DiffInfo,
prefs: DiffPreferencesInfo,
outputEl: HTMLElement,
- readonly layers: DiffLayer[] = []
+ readonly layers: DiffLayer[] = [],
+ renderPrefs?: RenderPreferences
) {
- super(diff, prefs, outputEl, layers);
+ super(diff, prefs, outputEl, layers, renderPrefs);
}
_getMoveControlsConfig() {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
index 4943298..3c8150c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
@@ -16,7 +16,10 @@
*/
import {
ContentLoadNeededEventDetail,
+ ContextButtonType,
+ DiffContextExpandedExternalDetail,
MovedLinkClickedEventDetail,
+ RenderPreferences,
} from '../../../api/diff';
import {getBaseUrl} from '../../../utils/url-util';
import {GrDiffLine, GrDiffLineType, LineNumber} from '../gr-diff/gr-diff-line';
@@ -30,6 +33,7 @@
import {DiffViewMode, Side} from '../../../constants/constants';
import {DiffLayer} from '../../../types/types';
import {pluralize} from '../../../utils/string-util';
+import {fire} from '../../../utils/event-util';
/**
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
@@ -55,18 +59,18 @@
const PARTIAL_CONTEXT_AMOUNT = 10;
-enum ContextButtonType {
- ABOVE = 'above',
- BELOW = 'below',
- ALL = 'all',
+export interface DiffContextExpandedEventDetail
+ extends DiffContextExpandedExternalDetail {
+ groups: GrDiffGroup[];
+ section: HTMLElement;
+ numLines: number;
}
-export interface ContextEvent extends Event {
- detail: {
- groups: GrDiffGroup[];
- section: HTMLElement;
- numLines: number;
- };
+declare global {
+ interface HTMLElementEventMap {
+ 'diff-context-expanded': CustomEvent<DiffContextExpandedEventDetail>;
+ 'content-load-needed': CustomEvent<ContentLoadNeededEventDetail>;
+ }
}
export abstract class GrDiffBuilder {
@@ -76,6 +80,8 @@
private readonly _prefs: DiffPreferencesInfo;
+ private readonly _renderPrefs?: RenderPreferences;
+
protected readonly _outputEl: HTMLElement;
readonly groups: GrDiffGroup[];
@@ -92,7 +98,8 @@
diff: DiffInfo,
prefs: DiffPreferencesInfo,
outputEl: HTMLElement,
- readonly layers: DiffLayer[] = []
+ readonly layers: DiffLayer[] = [],
+ renderPrefs?: RenderPreferences
) {
this._diff = diff;
this._numLinesLeft = this._diff.content
@@ -102,6 +109,7 @@
}, 0)
: 0;
this._prefs = prefs;
+ this._renderPrefs = renderPrefs;
this._outputEl = outputEl;
this.groups = [];
this.blameInfo = null;
@@ -147,13 +155,6 @@
REMOVED: 'edit_a',
};
- // TODO(TS): Replace usages with ContextButtonType enum.
- static readonly ContextButtonType = {
- ABOVE: 'above',
- BELOW: 'below',
- ALL: 'all',
- };
-
abstract addColumns(outputEl: HTMLElement, fontSize: number): void;
abstract buildSectionElement(group: GrDiffGroup): HTMLElement;
@@ -444,7 +445,8 @@
contextGroups: GrDiffGroup[],
numLines: number
) {
- const context = PARTIAL_CONTEXT_AMOUNT;
+ const linesToExpand =
+ type === ContextButtonType.ALL ? numLines : PARTIAL_CONTEXT_AMOUNT;
const button = this._createElement('gr-button', 'showContext');
button.classList.add('contextControlButton');
button.setAttribute('link', 'true');
@@ -453,11 +455,11 @@
let text = '';
let groups: GrDiffGroup[] = []; // The groups that replace this one if tapped.
let requiresLoad = false;
- if (type === GrDiffBuilder.ContextButtonType.ALL) {
- text = `+${pluralize(numLines, 'common line')}`;
+ if (type === ContextButtonType.ALL) {
+ text = `+${pluralize(linesToExpand, 'common line')}`;
button.setAttribute(
'aria-label',
- `Show ${pluralize(numLines, 'common line')}`
+ `Show ${pluralize(linesToExpand, 'common line')}`
);
requiresLoad = contextGroups.find(c => !!c.skip) !== undefined;
if (requiresLoad) {
@@ -465,21 +467,21 @@
text += ' (too large)';
}
groups.push(...contextGroups);
- } else if (type === GrDiffBuilder.ContextButtonType.ABOVE) {
- groups = hideInContextControl(contextGroups, context, numLines);
- text = `+${context}`;
+ } else if (type === ContextButtonType.ABOVE) {
+ groups = hideInContextControl(contextGroups, linesToExpand, numLines);
+ text = `+${linesToExpand}`;
button.classList.add('aboveButton');
button.setAttribute(
'aria-label',
- `Show ${pluralize(context, 'line')} above`
+ `Show ${pluralize(linesToExpand, 'line')} above`
);
- } else if (type === GrDiffBuilder.ContextButtonType.BELOW) {
- groups = hideInContextControl(contextGroups, 0, numLines - context);
- text = `+${context}`;
+ } else if (type === ContextButtonType.BELOW) {
+ groups = hideInContextControl(contextGroups, 0, numLines - linesToExpand);
+ text = `+${linesToExpand}`;
button.classList.add('belowButton');
button.setAttribute(
'aria-label',
- `Show ${pluralize(context, 'line')} below`
+ `Show ${pluralize(linesToExpand, 'line')} below`
);
}
const textSpan = this._createElement('span', 'showContext');
@@ -487,7 +489,7 @@
button.appendChild(textSpan);
if (requiresLoad) {
- button.addEventListener('tap', e => {
+ button.addEventListener('click', e => {
e.stopPropagation();
const firstRange = groups[0].lineRange;
const lastRange = groups[groups.length - 1].lineRange;
@@ -501,25 +503,20 @@
end_line: lastRange.right.end_line,
},
};
- button.dispatchEvent(
- new CustomEvent<ContentLoadNeededEventDetail>('content-load-needed', {
- detail: {
- lineRange,
- },
- bubbles: true,
- composed: true,
- })
- );
+ fire(button, 'content-load-needed', {
+ lineRange,
+ });
});
} else {
- button.addEventListener('tap', e => {
- const event = e as ContextEvent;
- event.detail = {
+ button.addEventListener('click', e => {
+ e.stopPropagation();
+ fire(button, 'diff-context-expanded', {
groups,
section,
numLines,
- };
- // Let it bubble up the DOM tree.
+ buttonType: type,
+ expandedLines: linesToExpand,
+ });
});
}
@@ -542,7 +539,9 @@
td.dataset['value'] = number.toString();
if (
- (this._prefs.show_file_comment_button === false && number === 'FILE') ||
+ ((this._prefs.show_file_comment_button === false ||
+ this._renderPrefs?.show_file_comment_button === false) &&
+ number === 'FILE') ||
number === 'LOST'
) {
return td;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
index cc3be07..9b7c25a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
@@ -25,8 +25,6 @@
} from '../../shared/gr-cursor-manager/gr-cursor-manager';
import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-cursor_html';
import {DiffViewMode} from '../../../api/diff';
@@ -38,6 +36,8 @@
import {GrDiffGroupType} from '../gr-diff/gr-diff-group';
import {GrDiff} from '../gr-diff/gr-diff';
import {fireAlert, fireEvent} from '../../../utils/event-util';
+import {Subscription} from 'rxjs';
+import {toggleClass} from '../../../utils/dom-util';
type GrDiffRowType = GrDiffLineType | GrDiffGroupType;
@@ -48,22 +48,18 @@
const NAVIGATE_TO_NEXT_FILE_TIMEOUT_MS = 5000;
export interface GrDiffCursor {
- $: {
- cursorManager: GrCursorManager;
- };
+ $: {};
}
@customElement('gr-diff-cursor')
-export class GrDiffCursor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffCursor extends PolymerElement {
static get template() {
return htmlTemplate;
}
private preventAutoScrollOnManualScroll = false;
- private lastDisplayedNavigateToNextFileToast: number | null = null;
+ private lastDisplayedNavigateToFileToast: Map<string, number> = new Map();
@property({type: String})
side = Side.RIGHT;
@@ -85,20 +81,18 @@
@property({type: Number})
initialLineNumber: number | null = null;
- /**
- * The scroll behavior for the cursor. Values are 'never' and
- * 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
- * the viewport.
- */
- @property({type: String})
- _scrollMode = ScrollMode.KEEP_VISIBLE;
-
- @property({type: Boolean})
- _focusOnMove = true;
-
@property({type: Boolean})
_listeningForScroll = false;
+ private cursorManager = new GrCursorManager();
+
+ constructor() {
+ super();
+ this.cursorManager.cursorTargetClass = 'target-row';
+ this.cursorManager.scrollMode = ScrollMode.KEEP_VISIBLE;
+ this.cursorManager.focusOnMove = true;
+ }
+
/** @override */
ready() {
super.ready();
@@ -122,27 +116,34 @@
});
}
+ private targetSubscription?: Subscription;
+
/** @override */
connectedCallback() {
super.connectedCallback();
// Catch when users are scrolling as the view loads.
window.addEventListener('scroll', this._boundHandleWindowScroll);
+ this.targetSubscription = this.cursorManager.target$.subscribe(target => {
+ this.diffRow = target || undefined;
+ });
}
/** @override */
disconnectedCallback() {
- super.disconnectedCallback();
+ if (this.targetSubscription) this.targetSubscription.unsubscribe();
window.removeEventListener('scroll', this._boundHandleWindowScroll);
+ this.cursorManager.unsetCursor();
+ super.disconnectedCallback();
}
// Don't remove - used by clients embedding gr-diff outside of Gerrit.
isAtStart() {
- return this.$.cursorManager.isAtStart();
+ return this.cursorManager.isAtStart();
}
// Don't remove - used by clients embedding gr-diff outside of Gerrit.
isAtEnd() {
- return this.$.cursorManager.isAtEnd();
+ return this.cursorManager.isAtEnd();
}
moveLeft() {
@@ -161,31 +162,54 @@
moveDown() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
- return this.$.cursorManager.next({
+ return this.cursorManager.next({
filter: (row: Element) => this._rowHasSide(row),
});
} else {
- return this.$.cursorManager.next();
+ return this.cursorManager.next();
}
}
moveUp() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
- return this.$.cursorManager.previous({
+ return this.cursorManager.previous({
filter: (row: Element) => this._rowHasSide(row),
});
} else {
- return this.$.cursorManager.previous();
+ return this.cursorManager.previous();
}
}
moveToVisibleArea() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
- this.$.cursorManager.moveToVisibleArea((row: Element) =>
+ this.cursorManager.moveToVisibleArea((row: Element) =>
this._rowHasSide(row)
);
} else {
- this.$.cursorManager.moveToVisibleArea();
+ this.cursorManager.moveToVisibleArea();
+ }
+ }
+
+ private showToastAndFireEvent(direction: string, shortcut: string) {
+ /*
+ * If user presses p/n on the first/last diff chunk, show a toast informing
+ * user that pressing it again will navigate them to previous/next
+ * unreviewedfile if click happens within the time limit
+ */
+ if (
+ this.lastDisplayedNavigateToFileToast.get(direction) &&
+ Date.now() - this.lastDisplayedNavigateToFileToast.get(direction)! <=
+ NAVIGATE_TO_NEXT_FILE_TIMEOUT_MS
+ ) {
+ // reset for next file
+ this.lastDisplayedNavigateToFileToast.delete(direction);
+ fireEvent(this, `navigate-to-${direction}-unreviewed-file`);
+ } else {
+ this.lastDisplayedNavigateToFileToast.set(direction, Date.now());
+ fireAlert(
+ this,
+ `Press ${shortcut} again to navigate to ${direction} unreviewed file`
+ );
}
}
@@ -193,44 +217,31 @@
clipToTop?: boolean,
navigateToNextFile?: boolean
): CursorMoveResult {
- const result = this.$.cursorManager.next({
+ const result = this.cursorManager.next({
filter: (row: HTMLElement) => this._isFirstRowOfChunk(row),
getTargetHeight: target =>
(target?.parentNode as HTMLElement)?.scrollHeight || 0,
clipToTop,
});
- /*
- * If user presses n on the last diff chunk, show a toast informing user
- * that pressing n again will navigate them to next unreviewed file.
- * If click happens within the time limit, then navigate to next file
- */
if (
navigateToNextFile &&
result === CursorMoveResult.CLIPPED &&
this.isAtEnd()
) {
- if (
- this.lastDisplayedNavigateToNextFileToast &&
- Date.now() - this.lastDisplayedNavigateToNextFileToast <=
- NAVIGATE_TO_NEXT_FILE_TIMEOUT_MS
- ) {
- // reset for next file
- this.lastDisplayedNavigateToNextFileToast = null;
- fireEvent(this, 'navigate-to-next-unreviewed-file');
- } else {
- this.lastDisplayedNavigateToNextFileToast = Date.now();
- fireAlert(this, 'Press n again to navigate to next unreviewed file');
- }
+ this.showToastAndFireEvent('next', 'n');
}
this._fixSide();
return result;
}
- moveToPreviousChunk(): CursorMoveResult {
- const result = this.$.cursorManager.previous({
+ moveToPreviousChunk(navigateToPreviousFile?: boolean): CursorMoveResult {
+ const result = this.cursorManager.previous({
filter: (row: HTMLElement) => this._isFirstRowOfChunk(row),
});
+ if (navigateToPreviousFile && this.isAtStart()) {
+ this.showToastAndFireEvent('previous', 'p');
+ }
this._fixSide();
return result;
}
@@ -240,7 +251,7 @@
fireEvent(this, 'navigate-to-next-file-with-comments');
return;
}
- const result = this.$.cursorManager.next({
+ const result = this.cursorManager.next({
filter: (row: HTMLElement) => this._rowHasThread(row),
});
this._fixSide();
@@ -248,7 +259,7 @@
}
moveToPreviousCommentThread(): CursorMoveResult {
- const result = this.$.cursorManager.previous({
+ const result = this.cursorManager.previous({
filter: (row: HTMLElement) => this._rowHasThread(row),
});
this._fixSide();
@@ -259,7 +270,7 @@
const row = this._findRowByNumberAndFile(number, side, path);
if (row) {
this.side = side;
- this.$.cursorManager.setCursor(row);
+ this.cursorManager.setCursor(row);
}
}
@@ -291,7 +302,7 @@
}
moveToFirstChunk() {
- this.$.cursorManager.moveToStart();
+ this.cursorManager.moveToStart();
if (this.diffRow && !this._isFirstRowOfChunk(this.diffRow)) {
this.moveToNextChunk(true);
} else {
@@ -300,7 +311,7 @@
}
moveToLastChunk() {
- this.$.cursorManager.moveToEnd();
+ this.cursorManager.moveToEnd();
if (this.diffRow && !this._isFirstRowOfChunk(this.diffRow)) {
this.moveToPreviousChunk();
} else {
@@ -320,7 +331,7 @@
reInitCursor() {
if (!this.diffRow) {
// does not scroll during init unless requested
- this._scrollMode = this.initialLineNumber
+ this.cursorManager.scrollMode = this.initialLineNumber
? ScrollMode.KEEP_VISIBLE
: ScrollMode.NEVER;
if (this.initialLineNumber) {
@@ -334,13 +345,13 @@
}
reInit() {
- this._scrollMode = ScrollMode.KEEP_VISIBLE;
+ this.cursorManager.scrollMode = ScrollMode.KEEP_VISIBLE;
}
private _boundHandleWindowScroll = () => {
if (this.preventAutoScrollOnManualScroll) {
- this._scrollMode = ScrollMode.NEVER;
- this._focusOnMove = false;
+ this.cursorManager.scrollMode = ScrollMode.NEVER;
+ this.cursorManager.focusOnMove = false;
this.preventAutoScrollOnManualScroll = false;
}
};
@@ -366,7 +377,7 @@
private _boundHandleDiffRenderContent = () => {
this._updateStops();
// When done rendering, turn focus on move and automatic scrolling back on
- this._focusOnMove = true;
+ this.cursorManager.focusOnMove = true;
this.preventAutoScrollOnManualScroll = false;
};
@@ -501,8 +512,8 @@
if (!this.diffRow) {
return;
}
- this.toggleClass(LEFT_SIDE_CLASS, this.side === Side.LEFT, this.diffRow);
- this.toggleClass(RIGHT_SIDE_CLASS, this.side === Side.RIGHT, this.diffRow);
+ toggleClass(this.diffRow, LEFT_SIDE_CLASS, this.side === Side.LEFT);
+ toggleClass(this.diffRow, RIGHT_SIDE_CLASS, this.side === Side.RIGHT);
}
_isActionType(type: GrDiffRowType) {
@@ -525,7 +536,7 @@
}
_updateStops() {
- this.$.cursorManager.stops = this.diffs.reduce(
+ this.cursorManager.stops = this.diffs.reduce(
(stops: Stop[], diff) => stops.concat(diff.getCursorStops()),
[]
);
@@ -604,7 +615,7 @@
const diff = this.diffs.filter(diff => diff.path === path)[0];
stops = diff.getCursorStops();
} else {
- stops = this.$.cursorManager.stops;
+ stops = this.cursorManager.stops;
}
// Sadly needed for type narrowing to understand that the result is always
// targetable.
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.ts
index 1539a22..1489006 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_html.ts
@@ -16,12 +16,4 @@
*/
import {html} from '@polymer/polymer/lib/utils/html-tag';
-export const htmlTemplate = html`
- <gr-cursor-manager
- id="cursorManager"
- scroll-mode="[[_scrollMode]]"
- cursor-target-class="target-row"
- focus-on-move="[[_focusOnMove]]"
- target="{{diffRow}}"
- ></gr-cursor-manager>
-`;
+export const htmlTemplate = html``;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
index 60b82da..75439c8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
@@ -187,20 +187,20 @@
});
test('cursor scroll behavior', () => {
- assert.equal(cursorElement._scrollMode, 'keep-visible');
+ assert.equal(cursorElement.cursorManager.scrollMode, 'keep-visible');
diffElement.dispatchEvent(new Event('render-start'));
- assert.isTrue(cursorElement._focusOnMove);
+ assert.isTrue(cursorElement.cursorManager.focusOnMove);
window.dispatchEvent(new Event('scroll'));
- assert.equal(cursorElement._scrollMode, 'never');
- assert.isFalse(cursorElement._focusOnMove);
+ assert.equal(cursorElement.cursorManager.scrollMode, 'never');
+ assert.isFalse(cursorElement.cursorManager.focusOnMove);
diffElement.dispatchEvent(new Event('render-content'));
- assert.isTrue(cursorElement._focusOnMove);
+ assert.isTrue(cursorElement.cursorManager.focusOnMove);
cursorElement.reInitCursor();
- assert.equal(cursorElement._scrollMode, 'keep-visible');
+ assert.equal(cursorElement.cursorManager.scrollMode, 'keep-visible');
});
test('moves to selected line', () => {
@@ -266,7 +266,7 @@
// to the right side.
assert.equal(cursorElement.side, 'right');
assert.equal(cursorElement.diffRow, firstDeltaRow);
- const firstIndex = cursorElement.$.cursorManager.index;
+ const firstIndex = cursorElement.cursorManager.index;
// Move the side to the left. Because this delta only has a right side, we
// should be moved up to the previous line where there is content on the
@@ -275,7 +275,7 @@
assert.equal(cursorElement.side, 'left');
assert.notEqual(cursorElement.diffRow, firstDeltaRow);
- assert.equal(cursorElement.$.cursorManager.index, firstIndex - 1);
+ assert.equal(cursorElement.cursorManager.index, firstIndex - 1);
assert.equal(cursorElement.diffRow.parentElement,
firstDeltaSection.previousSibling);
@@ -285,7 +285,7 @@
assert.equal(cursorElement.side, 'left');
assert.notEqual(cursorElement.diffRow, firstDeltaRow);
- assert.isTrue(cursorElement.$.cursorManager.index > firstIndex);
+ assert.isTrue(cursorElement.cursorManager.index > firstIndex);
assert.equal(cursorElement.diffRow.parentElement,
firstDeltaSection.nextSibling);
});
@@ -446,8 +446,7 @@
});
test('navigate to next unreviewed file via moveToNextChunk', () => {
- const cursorManager =
- cursorElement.shadowRoot.querySelector('#cursorManager');
+ const cursorManager = cursorElement.cursorManager;
cursorManager.index = cursorManager.stops.length - 1;
const dispatchEventStub = sinon.stub(cursorElement, 'dispatchEvent');
cursorElement.moveToNextChunk(/* opt_clipToTop = */false,
@@ -465,8 +464,9 @@
let scrollBehaviorDuringMove;
const moveToNumStub = sinon.stub(cursorElement, 'moveToLineNumber');
const moveToChunkStub = sinon.stub(cursorElement, 'moveToFirstChunk')
- .callsFake(
- () => { scrollBehaviorDuringMove = cursorElement._scrollMode; });
+ .callsFake(() => {
+ scrollBehaviorDuringMove = cursorElement.cursorManager.scrollMode;
+ });
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
@@ -474,7 +474,7 @@
assert.isFalse(moveToNumStub.called);
assert.isTrue(moveToChunkStub.called);
assert.equal(scrollBehaviorDuringMove, 'never');
- assert.equal(cursorElement._scrollMode, 'keep-visible');
+ assert.equal(cursorElement.cursorManager.scrollMode, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
@@ -484,8 +484,9 @@
test('initialLineNumber provided', done => {
let scrollBehaviorDuringMove;
const moveToNumStub = sinon.stub(cursorElement, 'moveToLineNumber')
- .callsFake(
- () => { scrollBehaviorDuringMove = cursorElement._scrollMode; });
+ .callsFake(() => {
+ scrollBehaviorDuringMove = cursorElement.cursorManager.scrollMode;
+ });
const moveToChunkStub = sinon.stub(cursorElement, 'moveToFirstChunk');
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
@@ -495,7 +496,7 @@
assert.equal(moveToNumStub.lastCall.args[0], 10);
assert.equal(moveToNumStub.lastCall.args[1], 'right');
assert.equal(scrollBehaviorDuringMove, 'keep-visible');
- assert.equal(cursorElement._scrollMode, 'keep-visible');
+ assert.equal(cursorElement.cursorManager.scrollMode, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
@@ -600,7 +601,7 @@
{leftSide: true, number: 10});
// Should be null if there is no selection.
- cursorElement.$.cursorManager.unsetCursor();
+ cursorElement.cursorManager.unsetCursor();
assert.isNotOk(cursorElement.getAddress());
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
index 094f2d7..76e02f0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -17,8 +17,6 @@
import '../../../styles/shared-styles';
import '../gr-selection-action-box/gr-selection-action-box';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-highlight_html';
import {GrAnnotation} from './gr-annotation';
@@ -31,6 +29,7 @@
import {GrDiffBuilderElement} from '../gr-diff-builder/gr-diff-builder-element';
import {FILE} from '../gr-diff/gr-diff-line';
import {getRange, getSide} from '../gr-diff/gr-diff-utils';
+import {debounce, DelayedTask} from '../../../utils/async-util';
interface SidedRange {
side: Side;
@@ -54,12 +53,8 @@
rootId: string;
}
-const DEBOUNCER_SELECTION_CHANGE = 'selectionChange';
-
@customElement('gr-diff-highlight')
-export class GrDiffHighlight extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffHighlight extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -76,9 +71,10 @@
@property({type: Object, notify: true})
selectedRange?: SidedRange;
- /** @override */
- created() {
- super.created();
+ private selectionChangeTask?: DelayedTask;
+
+ constructor() {
+ super();
this.addEventListener('comment-thread-mouseleave', e =>
this._handleCommentThreadMouseleave(e)
);
@@ -91,8 +87,9 @@
}
/** @override */
- detached() {
- this.cancelDebouncer(DEBOUNCER_SELECTION_CHANGE);
+ disconnectedCallback() {
+ this.selectionChangeTask?.cancel();
+ super.disconnectedCallback();
}
get diffBuilder() {
@@ -129,8 +126,8 @@
// quick 'c' press after the selection change. If you wait less than 10
// ms, then you will have about 50 _handleSelection calls when doing a
// simple drag for select.
- this.debounce(
- DEBOUNCER_SELECTION_CHANGE,
+ this.selectionChangeTask = debounce(
+ this.selectionChangeTask,
() => this._handleSelection(selection, isMouseUp),
10
);
@@ -171,11 +168,11 @@
rangeNodes.forEach(rangeNode => {
rangeNode.classList.add('rangeHoverHighlight');
});
- const chipNode = threadEl.parentElement?.querySelector(
- `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+ const hintNode = threadEl.parentElement?.querySelector(
+ `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
);
- if (chipNode) {
- chipNode.shadowRoot
+ if (hintNode) {
+ hintNode.shadowRoot
?.querySelectorAll('.rangeHighlight')
.forEach(highlightNode =>
highlightNode.classList.add('rangeHoverHighlight')
@@ -188,11 +185,11 @@
rangeNodes.forEach(rangeNode => {
rangeNode.classList.remove('rangeHoverHighlight');
});
- const chipNode = threadEl.parentElement?.querySelector(
- `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+ const hintNode = threadEl.parentElement?.querySelector(
+ `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
);
- if (chipNode) {
- chipNode.shadowRoot
+ if (hintNode) {
+ hintNode.shadowRoot
?.querySelectorAll('.rangeHoverHighlight')
.forEach(highlightNode =>
highlightNode.classList.remove('rangeHoverHighlight')
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
index 11b1f38..07e83a8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
@@ -266,10 +266,8 @@
setup(() => {
contentStubs = [];
- stub('gr-selection-action-box', {
- placeAbove: sinon.stub(),
- placeBelow: sinon.stub(),
- });
+ stub('gr-selection-action-box', 'placeAbove');
+ stub('gr-selection-action-box', 'placeBelow');
diff = element.querySelector('#diffTable');
builder = {
getContentTdByLine: sinon.stub(),
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index 47b4a1f..1f4b778 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -16,9 +16,6 @@
*/
import '../../shared/gr-comment-thread/gr-comment-thread';
import '../gr-diff/gr-diff';
-import '../gr-syntax-layer/gr-syntax-layer';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-host_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -72,14 +69,18 @@
import {FilesWebLinks} from '../gr-patch-range-select/gr-patch-range-select';
import {LineNumber, FILE} from '../gr-diff/gr-diff-line';
import {GrCommentThread} from '../../shared/gr-comment-thread/gr-comment-thread';
+import {KnownExperimentId} from '../../../services/flags/flags';
import {
firePageError,
fireAlert,
fireServerError,
fireEvent,
+ waitForEventOnce,
} from '../../../utils/event-util';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {assertIsDefined} from '../../../utils/common-util';
+import {DiffContextExpandedEventDetail} from '../gr-diff-builder/gr-diff-builder';
+import {Timing} from '../../../constants/reporting';
const MSG_EMPTY_BLAME = 'No blame information for this diff.';
@@ -87,12 +88,6 @@
const EVENT_ZERO_REBASE = 'rebase-percent-zero';
const EVENT_NONZERO_REBASE = 'rebase-percent-nonzero';
-const TimingLabel = {
- TOTAL: 'Diff Total Render',
- CONTENT: 'Diff Content Render',
- SYNTAX: 'Diff Syntax Render',
-};
-
// Disable syntax highlighting if the overall diff is too large.
const SYNTAX_MAX_DIFF_LENGTH = 20000;
@@ -119,7 +114,6 @@
export interface GrDiffHost {
$: {
- syntaxLayer: GrSyntaxLayer & Element;
diff: GrDiff;
};
}
@@ -132,9 +126,7 @@
* specific component, while <gr-diff> is a re-usable component.
*/
@customElement('gr-diff-host')
-export class GrDiffHost extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffHost extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -237,7 +229,7 @@
@property({type: Object})
_revisionImage: Base64ImageFile | null = null;
- @property({type: Object, notify: true})
+ @property({type: Object, notify: true, observer: 'diffChanged'})
diff?: DiffInfo;
@property({type: Object})
@@ -258,6 +250,7 @@
@property({
type: Boolean,
computed: '_isSyntaxHighlightingEnabled(prefs.*, diff)',
+ observer: '_syntaxHighlightingEnabledChanged',
})
_syntaxHighlightingEnabled?: boolean;
@@ -266,13 +259,16 @@
private readonly reporting = appContext.reportingService;
+ private readonly flags = appContext.flagsService;
+
private readonly restApiService = appContext.restApiService;
private readonly jsAPI = appContext.jsApiService;
- /** @override */
- created() {
- super.created();
+ private readonly syntaxLayer = new GrSyntaxLayer();
+
+ constructor() {
+ super();
this.addEventListener(
// These are named inconsistently for a reason:
// The create-comment event is fired to indicate that we should
@@ -308,17 +304,17 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getLoggedIn().then(loggedIn => {
this._loggedIn = loggedIn;
});
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
this.clear();
+ super.disconnectedCallback();
}
initLayers() {
@@ -326,8 +322,7 @@
.awaitPluginsLoaded()
.then(() => {
assertIsDefined(this.path, 'path');
- assertIsDefined(this.changeNum, 'changeNum');
- this._layers = this._getLayers(this.path, this.changeNum);
+ this._layers = this._getLayers(this.path);
this._coverageRanges = [];
// We kick off fetching the data here, but we don't return the promise,
// so awaiting initLayers() will not wait for coverage data to be
@@ -336,6 +331,10 @@
});
}
+ diffChanged(diff?: DiffInfo) {
+ this.syntaxLayer.init(diff);
+ }
+
/**
* @param shouldReportMetric indicate a new Diff Page. This is a
* signal to report metrics event that started on location change.
@@ -374,7 +373,7 @@
this.filesWeblinks = this._getFilesWeblinks(diff);
this.diff = diff;
- const event = await this._onRenderOnce();
+ const event = (await waitForEventOnce(this, 'render')) as CustomEvent;
if (shouldReportMetric) {
// We report diffViewContentDisplayed only on reload caused
// by params changed - expected only on Diff Page.
@@ -382,11 +381,11 @@
}
const needsSyntaxHighlighting = !!event.detail?.contentRendered;
if (needsSyntaxHighlighting) {
- this.reporting.time(TimingLabel.SYNTAX);
+ this.reporting.time(Timing.DIFF_SYNTAX);
try {
- await this.$.syntaxLayer.process();
+ await this.syntaxLayer.process();
} finally {
- this.reporting.timeEnd(TimingLabel.SYNTAX);
+ this.reporting.timeEnd(Timing.DIFF_SYNTAX);
}
}
} catch (e) {
@@ -396,23 +395,13 @@
console.warn('Error encountered loading diff:', e);
}
} finally {
- this.reporting.timeEnd(TimingLabel.TOTAL);
+ this.reporting.timeEnd(Timing.DIFF_TOTAL);
}
}
- private _getLayers(path: string, changeNum: NumericChangeId): DiffLayer[] {
+ private _getLayers(path: string): DiffLayer[] {
// Get layers from plugins (if any).
- return [this.$.syntaxLayer, ...this.jsAPI.getDiffLayers(path, changeNum)];
- }
-
- private _onRenderOnce(): Promise<CustomEvent> {
- return new Promise<CustomEvent>(resolve => {
- const callback = (event: CustomEvent) => {
- this.removeEventListener('render', callback);
- resolve(event);
- };
- this.addEventListener('render', callback);
- });
+ return [this.syntaxLayer, ...this.jsAPI.getDiffLayers(path)];
}
clear() {
@@ -510,7 +499,7 @@
/** Cancel any remaining diff builder rendering work. */
cancel() {
this.$.diff.cancel();
- this.$.syntaxLayer.cancel();
+ this.syntaxLayer.cancel();
}
getCursorStops() {
@@ -1001,6 +990,10 @@
fireEvent(this, 'diff-comments-modified');
}
+ _syntaxHighlightingEnabledChanged(_syntaxHighlightingEnabled: boolean) {
+ this.syntaxLayer.setEnabled(_syntaxHighlightingEnabled);
+ }
+
_isSyntaxHighlightingEnabled(
preferenceChangeRecord?: PolymerDeepPropertyChange<
DiffPreferencesInfo,
@@ -1014,16 +1007,16 @@
if (this._anyLineTooLong(diff)) {
fireAlert(
this,
- `A line is longer than ${SYNTAX_MAX_LINE_LENGTH}.` +
- ' Syntax Highlighting was turned off.'
+ `Files with line longer than ${SYNTAX_MAX_LINE_LENGTH} characters` +
+ ' will not be syntax highlighted.'
);
return false;
}
if (this.$.diff.getDiffLength(diff) > SYNTAX_MAX_DIFF_LENGTH) {
fireAlert(
this,
- `A diff is longer than ${SYNTAX_MAX_DIFF_LENGTH}.` +
- ' Syntax Highlighting was turned off.'
+ `Files with more than ${SYNTAX_MAX_DIFF_LENGTH} lines` +
+ ' will not be syntax highlighted.'
);
return false;
}
@@ -1048,20 +1041,20 @@
const renderUpdateListener: DiffLayerListener = start => {
if (start > NUM_OF_LINES_THRESHOLD_FOR_VIEWPORT) {
this.reporting.diffViewDisplayed();
- this.$.syntaxLayer.removeListener(renderUpdateListener);
+ this.syntaxLayer.removeListener(renderUpdateListener);
}
};
- this.$.syntaxLayer.addListener(renderUpdateListener);
+ this.syntaxLayer.addListener(renderUpdateListener);
}
_handleRenderStart() {
- this.reporting.time(TimingLabel.TOTAL);
- this.reporting.time(TimingLabel.CONTENT);
+ this.reporting.time(Timing.DIFF_TOTAL);
+ this.reporting.time(Timing.DIFF_CONTENT);
}
_handleRenderContent() {
- this.reporting.timeEnd(TimingLabel.CONTENT);
+ this.reporting.timeEnd(Timing.DIFF_CONTENT);
}
_handleNormalizeRange(event: CustomEvent) {
@@ -1071,9 +1064,9 @@
});
}
- _handleDiffContextExpanded(event: CustomEvent) {
+ _handleDiffContextExpanded(e: CustomEvent<DiffContextExpandedEventDetail>) {
this.reporting.reportInteraction('diff-context-expanded', {
- numLines: event.detail.numLines,
+ numLines: e.detail.numLines,
});
}
@@ -1145,6 +1138,10 @@
_showNewlineWarningRight(diff?: DiffInfo) {
return this._hasTrailingNewlines(diff, false) === false;
}
+
+ _useNewImageDiffUi() {
+ return this.flags.isEnabled(KnownExperimentId.NEW_IMAGE_DIFF_UI);
+ }
}
declare global {
@@ -1159,7 +1156,7 @@
/* prettier-ignore */
'render': CustomEvent;
'normalize-range': CustomEvent;
- 'diff-context-expanded': CustomEvent;
+ 'diff-context-expanded': CustomEvent<DiffContextExpandedEventDetail>;
'create-comment': CustomEvent;
'comment-discard': CustomEvent;
'comment-update': CustomEvent;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
index 84a2e4a..3dd2b24 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
@@ -40,11 +40,7 @@
diff="[[diff]]"
show-newline-warning-left="[[_showNewlineWarningLeft(diff)]]"
show-newline-warning-right="[[_showNewlineWarningRight(diff)]]"
+ use-new-image-diff-ui="[[_useNewImageDiffUi()]]"
>
</gr-diff>
- <gr-syntax-layer
- id="syntaxLayer"
- enabled="[[_syntaxHighlightingEnabled]]"
- diff="[[diff]]"
- ></gr-syntax-layer>
`;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
index 01c78f0..5e1b5ff 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
@@ -21,11 +21,10 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {createCommentThreads} from '../../../utils/comment-util.js';
-import {Side} from '../../../constants/constants.js';
+import {Side, createDefaultDiffPrefs} from '../../../constants/constants.js';
import {createChange} from '../../../test/test-data-generators.js';
import {CoverageType} from '../../../types/types.js';
import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
-import {createDefaultDiffPrefs} from '../../../constants/constants.js';
import {EditPatchSetNum, ParentPatchSetNum} from '../../../types/common.js';
const basicFixture = fixtureFromElement('gr-diff-host');
@@ -103,8 +102,7 @@
threadEls[0].dispatchEvent(
new CustomEvent('thread-discard', {detail: {rootId: 4711}}));
- const attachedThreads = element.queryAllEffectiveChildren(
- 'gr-comment-thread');
+ const attachedThreads = element.querySelectorAll('gr-comment-thread');
assert.equal(attachedThreads.length, 1);
assert.equal(attachedThreads[0].comments[0].id, 42);
});
@@ -130,7 +128,7 @@
test('ends total and syntax timer after syntax layer', async () => {
sinon.stub(element.reporting, 'diffViewContentDisplayed');
let notifySyntaxProcessed;
- sinon.stub(element.$.syntaxLayer, 'process').returns(
+ sinon.stub(element.syntaxLayer, 'process').returns(
new Promise(resolve => {
notifySyntaxProcessed = resolve;
})
@@ -159,6 +157,7 @@
element.reload();
// Multiple cascading microtasks are scheduled.
await flush();
+ await flush();
// Reporting can be called with other parameters (ex. PluginsLoaded),
// but only 'Diff Total Render' is important in this test.
assert.equal(
@@ -170,7 +169,7 @@
test('completes reload promise after syntax layer processing', async () => {
let notifySyntaxProcessed;
- sinon.stub(element.$.syntaxLayer, 'process').returns(new Promise(
+ sinon.stub(element.syntaxLayer, 'process').returns(new Promise(
resolve => {
notifySyntaxProcessed = resolve;
}));
@@ -405,7 +404,7 @@
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile1.body);
+ 'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
leftLoaded = true;
if (rightLoaded) {
@@ -417,7 +416,7 @@
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile2.body);
+ 'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
rightLoaded = true;
@@ -496,7 +495,7 @@
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile1.body);
+ 'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
leftLoaded = true;
if (rightLoaded) {
@@ -508,7 +507,7 @@
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile2.body);
+ 'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
rightLoaded = true;
@@ -970,7 +969,7 @@
suite('create-comment', () => {
setup(async () => {
loggedIn = true;
- element.attached();
+ element.connectedCallback();
await flush();
});
@@ -1292,7 +1291,7 @@
test('gr-diff-host provides syntax highlighting layer', async () => {
stubRestApi('getDiff').returns(Promise.resolve({content: []}));
await element.reload();
- assert.equal(element.$.diff.layers[0], element.$.syntaxLayer);
+ assert.equal(element.$.diff.layers[0], element.syntaxLayer);
});
test('rendering normal-sized diff does not disable syntax', () => {
@@ -1301,7 +1300,7 @@
a: ['foo'],
}],
};
- assert.isTrue(element.$.syntaxLayer.enabled);
+ assert.isTrue(element.syntaxLayer.enabled);
});
test('rendering large diff disables syntax', () => {
@@ -1311,17 +1310,17 @@
a: [new Array(501).join('*')],
}],
};
- assert.isFalse(element.$.syntaxLayer.enabled);
+ assert.isFalse(element.syntaxLayer.enabled);
});
test('starts syntax layer processing on render event', async () => {
- sinon.stub(element.$.syntaxLayer, 'process')
+ sinon.stub(element.syntaxLayer, 'process')
.returns(Promise.resolve());
stubRestApi('getDiff').returns(Promise.resolve({content: []}));
await element.reload();
element.dispatchEvent(
new CustomEvent('render', {bubbles: true, composed: true}));
- assert.isTrue(element.$.syntaxLayer.process.called);
+ assert.isTrue(element.syntaxLayer.process.called);
});
});
@@ -1346,11 +1345,11 @@
test('gr-diff-host provides syntax highlighting layer', async () => {
stubRestApi('getDiff').returns(Promise.resolve({content: []}));
await element.reload();
- assert.equal(element.$.diff.layers[0], element.$.syntaxLayer);
+ assert.equal(element.$.diff.layers[0], element.syntaxLayer);
});
test('syntax layer should be disabled', () => {
- assert.isFalse(element.$.syntaxLayer.enabled);
+ assert.isFalse(element.syntaxLayer.enabled);
});
test('still disabled for large diff', () => {
@@ -1360,7 +1359,7 @@
a: [new Array(501).join('*')],
}],
};
- assert.isFalse(element.$.syntaxLayer.enabled);
+ assert.isFalse(element.syntaxLayer.enabled);
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts
new file mode 100644
index 0000000..77fe299
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts
@@ -0,0 +1,594 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '@polymer/paper-button/paper-button';
+import '@polymer/paper-card/paper-card';
+import '@polymer/paper-checkbox/paper-checkbox';
+import '@polymer/paper-dropdown-menu/paper-dropdown-menu';
+import '@polymer/paper-item/paper-item';
+import '@polymer/paper-listbox/paper-listbox';
+import './gr-overview-image';
+import './gr-zoomed-image';
+
+import {
+ css,
+ customElement,
+ html,
+ internalProperty,
+ LitElement,
+ property,
+ PropertyValues,
+ query,
+} from 'lit-element';
+import {classMap} from 'lit-html/directives/class-map';
+import {StyleInfo, styleMap} from 'lit-html/directives/style-map';
+
+import {Dimensions, fitToFrame, FrameConstrainer, Point, Rect} from './util';
+
+const DRAG_DEAD_ZONE_PIXELS = 5;
+
+/**
+ * This components allows the user to rapidly switch between two given images
+ * rendered in the same location, to make subtle differences more noticeable.
+ * Images can be magnified to compare details.
+ */
+@customElement('gr-image-viewer')
+export class GrImageViewer extends LitElement {
+ // URL for the image to use as base.
+ @property({type: String}) baseUrl = '';
+
+ // URL for the image to use as revision.
+ @property({type: String}) revisionUrl = '';
+
+ @internalProperty() protected baseSelected = true;
+
+ @internalProperty() protected scaledSelected = true;
+
+ @internalProperty() protected followMouse = false;
+
+ @internalProperty() protected scale = 1;
+
+ @internalProperty() protected checkerboardSelected = true;
+
+ @internalProperty() protected zoomedImageStyle: StyleInfo = {};
+
+ @query('.imageArea') protected imageArea!: HTMLDivElement;
+
+ @query('gr-zoomed-image') protected zoomedImage!: Element;
+
+ @query('#source-image') protected sourceImage!: HTMLImageElement;
+
+ private imageSize: Dimensions = {width: 0, height: 0};
+
+ @internalProperty()
+ protected magnifierSize: Dimensions = {width: 0, height: 0};
+
+ @internalProperty()
+ protected magnifierFrame: Rect = {
+ origin: {x: 0, y: 0},
+ dimensions: {width: 0, height: 0},
+ };
+
+ @internalProperty()
+ protected overviewFrame: Rect = {
+ origin: {x: 0, y: 0},
+ dimensions: {width: 0, height: 0},
+ };
+
+ protected readonly zoomLevels: Array<'fit' | number> = [
+ 'fit',
+ 1,
+ 1.25,
+ 1.5,
+ 1.75,
+ 2,
+ ];
+
+ @internalProperty() protected grabbing = false;
+
+ private ownsMouseDown = false;
+
+ private centerOnDown: Point = {x: 0, y: 0};
+
+ private pointerOnDown: Point = {x: 0, y: 0};
+
+ private readonly frameConstrainer = new FrameConstrainer();
+
+ private readonly resizeObserver = new ResizeObserver(
+ (entries: ResizeObserverEntry[]) => {
+ for (const entry of entries) {
+ if (entry.target === this.imageArea) {
+ this.magnifierSize = {
+ width: entry.contentRect.width,
+ height: entry.contentRect.height,
+ };
+ }
+ }
+ }
+ );
+
+ static styles = css`
+ :host {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ font-size: var(--font-size-normal);
+ --image-border-width: 2px;
+ }
+ .imageArea {
+ box-sizing: border-box;
+ flex-grow: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: var(--spacing-m);
+ padding: var(--image-border-width);
+ max-height: 100%;
+ }
+ #spacer {
+ visibility: hidden;
+ }
+ gr-zoomed-image {
+ border: var(--image-border-width) solid;
+ margin: calc(-1 * var(--image-border-width));
+ box-sizing: content-box;
+ position: absolute;
+ overflow: hidden;
+ cursor: pointer;
+ }
+ gr-zoomed-image.base {
+ border-color: var(--base-image-border-color, rgb(255, 205, 210));
+ }
+ gr-zoomed-image.revision {
+ border-color: var(--revision-image-border-color, rgb(170, 242, 170));
+ }
+ .checkerboard {
+ --square-size: var(--checkerboard-square-size, 10px);
+ --square-color: var(--checkerboard-square-color, #808080);
+ background-color: var(--checkerboard-background-color, #aaaaaa);
+ background-image: linear-gradient(
+ 45deg,
+ var(--square-color) 25%,
+ transparent 25%
+ ),
+ linear-gradient(-45deg, var(--square-color) 25%, transparent 25%),
+ linear-gradient(45deg, transparent 75%, var(--square-color) 75%),
+ linear-gradient(-45deg, transparent 75%, var(--square-color) 75%);
+ background-size: calc(var(--square-size) * 2) calc(var(--square-size) * 2);
+ background-position: 0 0, 0 var(--square-size),
+ var(--square-size) calc(-1 * var(--square-size)),
+ calc(-1 * var(--square-size)) 0;
+ }
+ .controls {
+ flex-grow: 0;
+ display: flex;
+ flex-direction: column;
+ align-self: flex-start;
+ margin: var(--spacing-m);
+ padding-bottom: var(--spacing-xl);
+ }
+ paper-button {
+ padding: var(--spacing-m);
+ font: var(--image-diff-button-font);
+ text-transform: var(--image-diff-button-text-transform, uppercase);
+ }
+ paper-button[unelevated] {
+ color: var(--primary-button-text-color);
+ background-color: var(--primary-button-background-color);
+ }
+ paper-button[outlined] {
+ color: var(--primary-button-background-color);
+ border-color: var(--primary-button-background-color);
+ }
+ #version-switcher {
+ display: flex;
+ margin: var(--spacing-xl);
+ }
+ #version-switcher paper-button {
+ flex-basis: 0;
+ flex-grow: 1;
+ margin: 0;
+ }
+ #version-explanation {
+ color: var(--deemphasized-text-color);
+ text-align: center;
+ margin: var(--spacing-xl);
+ }
+ gr-overview-image {
+ min-width: 200px;
+ min-height: 150px;
+ }
+ #zoom-control {
+ margin: 0 var(--spacing-xl);
+ }
+ #follow-mouse {
+ margin: var(--spacing-m) var(--spacing-xl) 0;
+ }
+ `;
+
+ render() {
+ const src = this.baseSelected ? this.baseUrl : this.revisionUrl;
+
+ const sourceImage = html`
+ <img
+ id="source-image"
+ src="${src}"
+ class="${classMap({
+ checkerboard: this.checkerboardSelected,
+ })}"
+ @load="${this.updateSizes}"
+ />
+ `;
+
+ const versionExplanation = html`
+ <div id="version-explanation">
+ This file is being ${this.revisionUrl ? 'added' : 'deleted'}.
+ </div>
+ `;
+
+ // This uses the unelevated and outlined attributes from mwc-button with
+ // manual styling, for a more seamless transition later.
+ const versionToggle = html`
+ <div id="version-switcher">
+ <paper-button
+ class="left"
+ ?unelevated=${this.baseSelected}
+ ?outlined=${!this.baseSelected}
+ @click="${this.selectBase}"
+ >
+ Base
+ </paper-button>
+ <paper-button
+ class="right"
+ ?unelevated=${!this.baseSelected}
+ ?outlined=${this.baseSelected}
+ @click="${this.selectRevision}"
+ >
+ Revision
+ </paper-button>
+ </div>
+ `;
+
+ const versionSwitcher = html`
+ ${this.baseUrl && this.revisionUrl ? versionToggle : versionExplanation}
+ `;
+
+ const overviewImage = html`
+ <gr-overview-image
+ .frameRect="${this.overviewFrame}"
+ @center-updated="${this.onOverviewCenterUpdated}"
+ >
+ <img src="${src}" class="checkerboard" />
+ </gr-overview-image>
+ `;
+
+ const zoomControl = html`
+ <paper-dropdown-menu id="zoom-control" label="Zoom">
+ <paper-listbox
+ slot="dropdown-content"
+ selected="fit"
+ attr-for-selected="value"
+ @selected-changed="${this.zoomControlChanged}"
+ >
+ ${this.zoomLevels.map(
+ zoomLevel => html`
+ <paper-item value="${zoomLevel}">
+ ${zoomLevel === 'fit' ? 'Fit' : `${zoomLevel * 100}%`}
+ </paper-item>
+ `
+ )}
+ </paper-listbox>
+ </paper-dropdown-menu>
+ `;
+
+ const followMouse = html`
+ <paper-checkbox
+ id="follow-mouse"
+ ?checked="${this.followMouse}"
+ @change="${this.followMouseChanged}"
+ >
+ Magnifier follows mouse
+ </paper-checkbox>
+ `;
+
+ /*
+ * We want the content to fill the available space until it can display
+ * without being cropped, the maximum of which will be determined by
+ * (max-)width and (max-)height constraints on the host element; but we
+ * are also limiting the displayed content to the measured dimensions of
+ * the host element without overflow, so we need something else to take up
+ * the requested space unconditionally.
+ */
+ const spacerScale = Math.max(this.scale, 1);
+ const spacerWidth = this.imageSize.width * spacerScale;
+ const spacerHeight = this.imageSize.height * spacerScale;
+ const spacer = html`
+ <div
+ id="spacer"
+ style="${styleMap({
+ width: `${spacerWidth}px`,
+ height: `${spacerHeight}px`,
+ })}"
+ ></div>
+ `;
+
+ // To pass CSS mixins for @apply to Polymer components, they need to be
+ // wrapped in a <custom-style>.
+ const customStyle = html`
+ <custom-style>
+ <style>
+ paper-button.left {
+ --paper-button: {
+ border-radius: 4px 0 0 4px;
+ border-width: 1px 0 1px 1px;
+ }
+ }
+ paper-button.left[outlined] {
+ --paper-button: {
+ border-radius: 4px 0 0 4px;
+ border-width: 1px 0 1px 1px;
+ border-style: solid;
+ border-color: var(--primary-button-background-color);
+ }
+ }
+ paper-button.right {
+ --paper-button: {
+ border-radius: 0 4px 4px 0;
+ border-width: 1px 1px 1px 0;
+ }
+ }
+ paper-button.right[outlined] {
+ --paper-button: {
+ border-radius: 0 4px 4px 0;
+ border-width: 1px 1px 1px 0;
+ border-style: solid;
+ border-color: var(--primary-button-background-color);
+ }
+ }
+ paper-item {
+ cursor: pointer;
+ --paper-item-min-height: 48;
+ --paper-item: {
+ min-height: 48px;
+ padding: 0 var(--spacing-xl);
+ }
+ --paper-item-focused-before: {
+ background-color: var(--selection-background-color);
+ }
+ --paper-item-focused: {
+ background-color: var(--selection-background-color);
+ }
+ }
+ }
+ paper-item:hover {
+ background-color: var(--hover-background-color);
+ }
+ </style>
+ </custom-style>
+ `;
+
+ return html`
+ ${customStyle}
+ <div class="imageArea" @mousemove="${this.mousemoveMagnifier}">
+ <gr-zoomed-image
+ class="${classMap({
+ base: this.baseSelected,
+ revision: !this.baseSelected,
+ })}"
+ style="${styleMap({
+ ...this.zoomedImageStyle,
+ cursor: this.grabbing ? 'grabbing' : 'pointer',
+ })}"
+ .scale="${this.scale}"
+ .frameRect="${this.magnifierFrame}"
+ @mousedown="${this.mousedownMagnifier}"
+ @mouseup="${this.mouseupMagnifier}"
+ @mousemove="${this.mousemoveMagnifier}"
+ @mouseleave="${this.mouseleaveMagnifier}"
+ @dragstart="${this.dragstartMagnifier}"
+ >
+ ${sourceImage}
+ </gr-zoomed-image>
+ ${spacer}
+ </div>
+
+ <paper-card class="controls">
+ ${versionSwitcher} ${overviewImage} ${zoomControl}
+ ${!this.scaledSelected ? followMouse : ''}
+ </paper-card>
+ `;
+ }
+
+ firstUpdated() {
+ this.resizeObserver.observe(this.imageArea, {box: 'content-box'});
+ }
+
+ // We don't want property changes in updateSizes() to trigger infinite update
+ // loops, so we perform this in update() instead of updated().
+ update(changedProperties: PropertyValues) {
+ if (!this.baseUrl) this.baseSelected = false;
+ if (!this.revisionUrl) this.baseSelected = true;
+ this.updateSizes();
+ super.update(changedProperties);
+ }
+
+ updated(changedProperties: PropertyValues) {
+ if (
+ (changedProperties.has('baseUrl') && this.baseSelected) ||
+ (changedProperties.has('revisionUrl') && !this.baseSelected)
+ ) {
+ this.frameConstrainer.requestCenter({x: 0, y: 0});
+ }
+ }
+
+ selectBase() {
+ if (!this.baseUrl) return;
+ this.baseSelected = true;
+ }
+
+ selectRevision() {
+ if (!this.revisionUrl) return;
+ this.baseSelected = false;
+ }
+
+ toggleImage() {
+ if (this.baseUrl && this.revisionUrl) {
+ this.baseSelected = !this.baseSelected;
+ }
+ }
+
+ zoomControlChanged(event: CustomEvent) {
+ const value = event.detail.value;
+ if (!value) return;
+ if (value === 'fit') {
+ this.scaledSelected = true;
+ }
+ if (value > 0) {
+ this.scaledSelected = false;
+ this.scale = value;
+ }
+ this.updateSizes();
+ }
+
+ followMouseChanged() {
+ this.followMouse = !this.followMouse;
+ }
+
+ mousedownMagnifier(event: MouseEvent) {
+ if (event.buttons === 1) {
+ this.ownsMouseDown = true;
+ this.centerOnDown = this.frameConstrainer.getCenter();
+ this.pointerOnDown = {
+ x: event.clientX,
+ y: event.clientY,
+ };
+ }
+ }
+
+ mouseupMagnifier(event: MouseEvent) {
+ const offsetX = event.clientX - this.pointerOnDown.x;
+ const offsetY = event.clientY - this.pointerOnDown.y;
+ const distance = Math.max(Math.abs(offsetX), Math.abs(offsetY));
+ // Consider very short drags as clicks. These tend to happen more often on
+ // external mice.
+ if (this.ownsMouseDown && distance < DRAG_DEAD_ZONE_PIXELS) {
+ this.toggleImage();
+ }
+ this.grabbing = false;
+ this.ownsMouseDown = false;
+ }
+
+ mousemoveMagnifier(event: MouseEvent) {
+ if (event.buttons === 1 && this.ownsMouseDown) {
+ this.handleMagnifierDrag(event);
+ return;
+ }
+ if (this.followMouse) {
+ this.handleFollowMouse(event);
+ return;
+ }
+ }
+
+ private handleMagnifierDrag(event: MouseEvent) {
+ this.grabbing = true;
+ const offsetX = event.clientX - this.pointerOnDown.x;
+ const offsetY = event.clientY - this.pointerOnDown.y;
+ this.frameConstrainer.requestCenter({
+ x: this.centerOnDown.x - offsetX / this.scale,
+ y: this.centerOnDown.y - offsetY / this.scale,
+ });
+ this.updateFrames();
+ }
+
+ private handleFollowMouse(event: MouseEvent) {
+ const rect = this.imageArea!.getBoundingClientRect();
+ const offsetX = event.clientX - rect.left;
+ const offsetY = event.clientY - rect.top;
+ const fractionX = offsetX / rect.width;
+ const fractionY = offsetY / rect.height;
+ this.frameConstrainer.requestCenter({
+ x: this.imageSize.width * fractionX,
+ y: this.imageSize.height * fractionY,
+ });
+ this.updateFrames();
+ }
+
+ mouseleaveMagnifier() {
+ this.grabbing = false;
+ this.ownsMouseDown = false;
+ }
+
+ dragstartMagnifier(event: DragEvent) {
+ event.preventDefault();
+ }
+
+ onOverviewCenterUpdated(event: CustomEvent) {
+ this.frameConstrainer.requestCenter({
+ x: event.detail.x as number,
+ y: event.detail.y as number,
+ });
+ this.updateFrames();
+ }
+
+ updateFrames() {
+ this.magnifierFrame = this.frameConstrainer.getUnscaledFrame();
+ this.overviewFrame = this.frameConstrainer.getScaledFrame();
+ }
+
+ updateSizes() {
+ if (!this.sourceImage || !this.sourceImage.complete) return;
+
+ this.imageSize = {
+ width: this.sourceImage.naturalWidth || 0,
+ height: this.sourceImage.naturalHeight || 0,
+ };
+
+ this.frameConstrainer.setBounds(this.imageSize);
+
+ if (this.scaledSelected) {
+ const fittedImage = fitToFrame(this.imageSize, this.magnifierSize);
+ this.scale = Math.min(fittedImage.scale, 1);
+ }
+
+ this.frameConstrainer.setScale(this.scale);
+
+ const scaledImageSize = {
+ width: this.imageSize.width * this.scale,
+ height: this.imageSize.height * this.scale,
+ };
+
+ const width = Math.min(this.magnifierSize.width, scaledImageSize.width);
+ const height = Math.min(this.magnifierSize.height, scaledImageSize.height);
+
+ this.frameConstrainer.setFrameSize({width, height});
+
+ this.updateFrames();
+
+ this.zoomedImageStyle = {
+ ...this.zoomedImageStyle,
+ width: `${width}px`,
+ height: `${height}px`,
+ };
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-image-viewer': GrImageViewer;
+ }
+}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
index 42268e9..aae559d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
@@ -50,8 +50,6 @@
@internalProperty() protected frameStyle: StyleInfo = {};
- @internalProperty() protected overlayStyle: StyleInfo = {};
-
@internalProperty() protected dragging = false;
@query('.content-box') protected contentBox!: HTMLDivElement;
@@ -62,6 +60,8 @@
@query('.frame') protected frame!: HTMLDivElement;
+ protected overlay?: HTMLDivElement;
+
private contentBounds: Dimensions = {width: 0, height: 0};
private imageBounds: Dimensions = {width: 0, height: 0};
@@ -94,8 +94,8 @@
static styles = css`
:host {
- --overview-image-background-color: #000;
- --overview-image-frame-color: #f00;
+ --background-color: var(--overview-image-background-color, #000);
+ --frame-color: var(--overview-image-frame-color, #f00);
display: flex;
}
* {
@@ -105,8 +105,8 @@
display: block;
}
.content-box {
- border: 1px solid var(--overview-image-background-color);
- background-color: var(--overview-iamge-background-color);
+ border: 1px solid var(--background-color);
+ background-color: var(--background-color);
width: 100%;
position: relative;
}
@@ -120,15 +120,10 @@
will-change: transform;
}
.frame {
- border: 1px solid var(--overview-image-frame-color);
+ border: 1px solid var(--frame-color);
position: absolute;
will-change: transform;
}
- .overlay {
- position: absolute;
- z-index: 10000;
- cursor: grabbing;
- }
`;
render() {
@@ -158,20 +153,51 @@
@mousedown="${this.grabFrame}"
></div>
</div>
- <div
- class="overlay"
- style="${styleMap({
- ...this.overlayStyle,
- display: this.dragging ? 'block' : 'none',
- })}"
- @mousemove="${this.overlayMouseMove}"
- @mouseleave="${this.releaseFrame}"
- @mouseup="${this.releaseFrame}"
- ></div>
</div>
`;
}
+ connectedCallback() {
+ super.connectedCallback();
+ if (this.isConnected) {
+ this.overlay = document.createElement('div');
+ // The overlay is added directly to document body to ensure it fills the
+ // entire screen to capture events, without being clipped by any parent
+ // overflow properties. This means it has to be styled manually, since
+ // component styles will not affect it.
+ this.overlay.style.position = 'fixed';
+ this.overlay.style.top = '0';
+ this.overlay.style.left = '0';
+ // We subtract 20 pixels in each dimension to prevent the overlay from
+ // extending offscreen under any existing scrollbar and causing the
+ // scrollbar for the other dimension to show up unnecessarily.
+ this.overlay.style.width = 'calc(100vw - 20px)';
+ this.overlay.style.height = 'calc(100vh - 20px)';
+ this.overlay.style.zIndex = '10000';
+ this.overlay.style.display = 'none';
+
+ this.overlay.addEventListener('mousemove', (event: MouseEvent) =>
+ this.maybeDragFrame(event)
+ );
+ this.overlay.addEventListener('mouseleave', (event: MouseEvent) =>
+ this.releaseFrame(event)
+ );
+ this.overlay.addEventListener('mouseup', (event: MouseEvent) =>
+ this.releaseFrame(event)
+ );
+
+ document.body.appendChild(this.overlay);
+ }
+ }
+
+ disconnectedCallback() {
+ if (this.overlay) {
+ document.body.removeChild(this.overlay);
+ this.overlay = undefined;
+ }
+ super.disconnectedCallback();
+ }
+
firstUpdated() {
this.resizeObserver.observe(this.contentBox);
this.resizeObserver.observe(this.contentTransform);
@@ -184,11 +210,12 @@
}
clickOverview(event: MouseEvent) {
+ if (event.buttons !== 1) return;
event.preventDefault();
- this.updateOverlaySize();
-
this.dragging = true;
+ this.openOverlay();
+
const rect = this.content.getBoundingClientRect();
this.notifyNewCenter({
x: (event.clientX - rect.left) / this.scale,
@@ -197,13 +224,14 @@
}
grabFrame(event: MouseEvent) {
+ if (event.buttons !== 1) return;
event.preventDefault();
// Do not bubble up into clickOverview().
event.stopPropagation();
- this.updateOverlaySize();
-
this.dragging = true;
+ this.openOverlay();
+
const rect = this.frame.getBoundingClientRect();
const frameCenterX = rect.x + rect.width / 2;
const frameCenterY = rect.y + rect.height / 2;
@@ -227,12 +255,22 @@
releaseFrame(event: MouseEvent) {
event.preventDefault();
this.dragging = false;
+ this.closeOverlay();
this.grabOffset = {x: 0, y: 0};
}
- overlayMouseMove(event: MouseEvent) {
- event.preventDefault();
- this.maybeDragFrame(event);
+ private openOverlay() {
+ if (this.overlay) {
+ this.overlay.style.display = 'block';
+ this.overlay.style.cursor = 'grabbing';
+ }
+ }
+
+ private closeOverlay() {
+ if (this.overlay) {
+ this.overlay.style.display = 'none';
+ this.overlay.style.cursor = '';
+ }
}
private updateScale() {
@@ -267,25 +305,6 @@
};
}
- private updateOverlaySize() {
- const rect = this.contentBox.getBoundingClientRect();
- // Create a whole-page overlay to capture mouse events, so that the drag
- // interaction continues until the user releases the mouse button. Since
- // innerWidth and innerHeight include scrollbars, we subtract 20 pixels each
- // to prevent the overlay from extending offscreen under any existing
- // scrollbar and causing the scrollbar for the other dimension to show up
- // unnecessarily.
- const width = window.innerWidth - 20;
- const height = window.innerHeight - 20;
- this.overlayStyle = {
- ...this.overlayStyle,
- top: `-${rect.top + 1}px`,
- left: `-${rect.left + 1}px`,
- width: `${width}px`,
- height: `${height}px`,
- };
- }
-
private notifyNewCenter(center: Point) {
this.dispatchEvent(
new CustomEvent('center-updated', {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
index 60f2853..b576896 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
@@ -19,19 +19,16 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import {DiffViewMode} from '../../../constants/constants';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-mode-selector_html';
import {customElement, property} from '@polymer/decorators';
import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announcer';
import {FixIronA11yAnnouncer} from '../../../types/types';
import {appContext} from '../../../services/app-context';
+import {fireIronAnnounce} from '../../../utils/event-util';
@customElement('gr-diff-mode-selector')
-export class GrDiffModeSelector extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffModeSelector extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -48,7 +45,9 @@
private readonly restApiService = appContext.restApiService;
- attached() {
+ /** @override */
+ connectedCallback() {
+ super.connectedCallback();
((IronA11yAnnouncer as unknown) as FixIronA11yAnnouncer).requestAvailability();
}
@@ -67,13 +66,7 @@
announcement = 'Changed diff view to side by side';
}
if (announcement) {
- this.fire(
- 'iron-announce',
- {
- text: announcement,
- },
- {bubbles: true}
- );
+ fireIronAnnounce(this, announcement);
}
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
index 8829afc..5a8c55d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-button/gr-button';
import '../../shared/gr-diff-preferences/gr-diff-preferences';
import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-preferences-dialog_html';
import {customElement, property} from '@polymer/decorators';
@@ -37,9 +35,7 @@
};
}
@customElement('gr-diff-preferences-dialog')
-export class GrDiffPreferencesDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffPreferencesDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
index 9fafcfa..d5e2a07 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {
GrDiffLine,
@@ -33,6 +31,7 @@
import {customElement, property} from '@polymer/decorators';
import {DiffContent} from '../../../types/diff';
import {Side} from '../../../constants/constants';
+import {debounce, DelayedTask} from '../../../utils/async-util';
const WHOLE_FILE = -1;
@@ -64,8 +63,6 @@
*/
const MAX_GROUP_SIZE = 120;
-const DEBOUNCER_RESET_IS_SCROLLING = 'resetIsScrolling';
-
/**
* Converts the API's `DiffContent`s to `GrDiffGroup`s for rendering.
*
@@ -92,9 +89,7 @@
* the rest is not.
*/
@customElement('gr-diff-processor')
-export class GrDiffProcessor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffProcessor extends PolymerElement {
@property({type: Number})
context = 3;
@@ -116,30 +111,30 @@
@property({type: Boolean})
_isScrolling?: boolean;
+ private resetIsScrollingTask?: DelayedTask;
+
/** @override */
- attached() {
- super.attached();
- this.listen(window, 'scroll', '_handleWindowScroll');
+ connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener('scroll', this.handleWindowScroll);
}
/** @override */
- detached() {
- super.detached();
- this.cancelDebouncer(DEBOUNCER_RESET_IS_SCROLLING);
+ disconnectedCallback() {
+ this.resetIsScrollingTask?.cancel();
this.cancel();
- this.unlisten(window, 'scroll', '_handleWindowScroll');
+ window.removeEventListener('scroll', this.handleWindowScroll);
+ super.disconnectedCallback();
}
- _handleWindowScroll() {
+ private readonly handleWindowScroll = () => {
this._isScrolling = true;
- this.debounce(
- DEBOUNCER_RESET_IS_SCROLLING,
- () => {
- this._isScrolling = false;
- },
+ this.resetIsScrollingTask = debounce(
+ this.resetIsScrollingTask,
+ () => (this._isScrolling = false),
50
);
- }
+ };
/**
* Asynchronously process the diff chunks into groups. As it processes, it
@@ -176,7 +171,7 @@
let currentBatch = 0;
const nextStep = () => {
if (this._isScrolling) {
- this._nextStepHandle = this.async(nextStep, 100);
+ this._nextStepHandle = window.setTimeout(nextStep, 100);
return;
}
// If we are done, resolve the promise.
@@ -199,7 +194,7 @@
state.chunkIndex = stateUpdate.newChunkIndex;
if (currentBatch >= this._asyncThreshold) {
currentBatch = 0;
- this._nextStepHandle = this.async(nextStep, 1);
+ this._nextStepHandle = window.setTimeout(nextStep, 1);
} else {
nextStep.call(this);
}
@@ -218,7 +213,7 @@
*/
cancel() {
if (this._nextStepHandle !== null) {
- this.cancelAsync(this._nextStepHandle);
+ window.clearTimeout(this._nextStepHandle);
this._nextStepHandle = null;
}
if (this._processPromise) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.js b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.js
index b8f7498..0bb5eac 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.js
@@ -750,7 +750,6 @@
],
};
const content = _.times(200, _.constant(contentRow));
- sinon.stub(element, 'async');
element._isScrolling = true;
element.process(content);
// Just the files group - no more processing during scrolling.
@@ -770,7 +769,6 @@
],
};
const content = _.times(200, _.constant(contentRow));
- sinon.stub(element, 'async');
element.process(content, true);
assert.equal(element.groups.length, 2);
@@ -1113,7 +1111,7 @@
test('detaching cancels', () => {
element = basicFixture.instantiate();
sinon.stub(element, 'cancel');
- element.detached();
+ element.disconnectedCallback();
assert(element.cancel.called);
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
index 9493478..3df2e18 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
@@ -17,8 +17,6 @@
import '../../../styles/shared-styles';
import {addListener} from '@polymer/polymer/lib/utils/gestures';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-selection_html';
import {
@@ -53,9 +51,7 @@
}
@customElement('gr-diff-selection')
-export class GrDiffSelection extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffSelection extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -69,16 +65,15 @@
@property({type: Object})
_linesCache: LinesCache = {left: null, right: null};
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('copy', e => this._handleCopy(e));
addListener(this, 'down', e => this._handleDown(e));
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.classList.add(SelectionClass.RIGHT);
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 2c4b8f6..4a51349 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -31,8 +31,6 @@
import '../gr-diff-preferences-dialog/gr-diff-preferences-dialog';
import '../gr-patch-range-select/gr-patch-range-select';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-view_html';
import {
@@ -64,6 +62,7 @@
import {ChangeComments, GrCommentApi} from '../gr-comment-api/gr-comment-api';
import {GrDiffModeSelector} from '../gr-diff-mode-selector/gr-diff-mode-selector';
import {
+ BasePatchSetNum,
ChangeInfo,
CommitId,
ConfigInfo,
@@ -78,6 +77,7 @@
PreferencesInfo,
RepoName,
RevisionInfo,
+ RevisionPatchSetNum,
} from '../../../types/common';
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {ChangeViewState, CommitRange, FileRange} from '../../../types/types';
@@ -95,9 +95,10 @@
} from '../../../utils/comment-util';
import {AppElementParams} from '../../gr-app-types';
import {CustomKeyboardEvent, OpenFixPreviewEvent} from '../../../types/events';
-import {fireAlert, fireTitleChange} from '../../../utils/event-util';
+import {fireAlert, fireEvent, fireTitleChange} from '../../../utils/event-util';
import {GerritView} from '../../../services/router/router-model';
import {assertIsDefined} from '../../../utils/common-util';
+import {toggleClass} from '../../../utils/dom-util';
const ERR_REVIEW_STATUS = 'Couldn’t change file review status.';
const MSG_LOADING_BLAME = 'Loading blame...';
const MSG_LOADED_BLAME = 'Blame loaded';
@@ -126,9 +127,7 @@
}
@customElement('gr-diff-view')
-export class GrDiffView extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrDiffView extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -326,11 +325,6 @@
this._throttledToggleFileReviewed = this._throttleWrap(e =>
this._handleToggleFileReviewed(e as CustomKeyboardEvent)
);
- }
-
- /** @override */
- attached() {
- super.attached();
this._getLoggedIn().then(loggedIn => {
this._loggedIn = loggedIn;
});
@@ -344,10 +338,11 @@
}
/** @override */
- detached() {
+ disconnectedCallback() {
if (this._onRenderHandler) {
this.$.diffHost.removeEventListener('render', this._onRenderHandler);
}
+ super.disconnectedCallback();
}
_getLoggedIn() {
@@ -641,18 +636,24 @@
this.$.cursor.moveToPreviousCommentThread();
} else {
if (this.modifierPressed(e)) return;
- this.$.cursor.moveToPreviousChunk();
+ this.$.cursor.moveToPreviousChunk(!e.detail.keyboardEvent?.repeat);
}
}
+ // Similar to gr-change-view._handleOpenReplyDialog
_handleOpenReplyDialog(e: CustomKeyboardEvent) {
if (this.shouldSuppressKeyboardShortcut(e)) return;
if (this.modifierPressed(e)) return;
- if (!this._loggedIn) return;
+ this._getLoggedIn().then(isLoggedIn => {
+ if (!isLoggedIn) {
+ fireEvent(this, 'show-auth-required');
+ return;
+ }
- this.set('changeViewState.showReplyDialog', true);
- e.preventDefault();
- this._navToChangeView();
+ this.set('changeViewState.showReplyDialog', true);
+ e.preventDefault();
+ this._navToChangeView();
+ });
}
_handleToggleLeftPane(e: CustomKeyboardEvent) {
@@ -1468,7 +1469,7 @@
const comparedAgainstParent = patchRange.basePatchNum === 'PARENT';
if (isBase && !comparedAgainstParent) {
- patchNum = patchRange.basePatchNum;
+ patchNum = patchRange.basePatchNum as RevisionPatchSetNum;
}
let url =
@@ -1621,7 +1622,7 @@
if (this.shouldSuppressKeyboardShortcut(e)) return;
if (this.modifierPressed(e)) return;
- this.toggleClass('hideComments');
+ toggleClass(this, 'hideComments');
}
_handleOpenFileList(e: CustomKeyboardEvent) {
@@ -1661,7 +1662,7 @@
this._change,
this._path,
this._patchRange.basePatchNum,
- 'PARENT' as PatchSetNum,
+ 'PARENT' as BasePatchSetNum,
this.params?.view === GerritView.DIFF && this.params?.commentLink
? this._focusLineNum
: undefined
@@ -1703,7 +1704,7 @@
this._change,
this._path,
latestPatchNum,
- this._patchRange.patchNum
+ this._patchRange.patchNum as BasePatchSetNum
);
}
@@ -1755,13 +1756,10 @@
return disableDiffPrefs || !loggedIn;
}
- _handleNextUnreviewedFile(e: CustomKeyboardEvent) {
- if (this.shouldSuppressKeyboardShortcut(e)) return;
+ _navigateToNextUnreviewedFile() {
if (!this._path) return;
if (!this._fileList) return;
if (!this._reviewedFiles) return;
-
- this._setReviewed(true);
// Ensure that the currently viewed file always appears in unreviewedFiles
// so we resolve the right "next" file.
const unreviewedFiles = this._fileList.filter(
@@ -1770,17 +1768,32 @@
this._navToFile(this._path, unreviewedFiles, 1);
}
+ _navigateToPreviousUnreviewedFile() {
+ if (!this._path) return;
+ if (!this._fileList) return;
+ if (!this._reviewedFiles) return;
+ // Ensure that the currently viewed file always appears in unreviewedFiles
+ // so we resolve the right "next" file.
+ const unreviewedFiles = this._fileList.filter(
+ file => file === this._path || !this._reviewedFiles.has(file)
+ );
+ this._navToFile(this._path, unreviewedFiles, -1);
+ }
+
+ _handleNextUnreviewedFile(e: CustomKeyboardEvent) {
+ if (this.shouldSuppressKeyboardShortcut(e)) return;
+ this._setReviewed(true);
+ this._navigateToNextUnreviewedFile();
+ }
+
_navigateToNextFileWithCommentThread() {
if (!this._path) return;
if (!this._fileList) return;
if (!this._patchRange) return;
if (!this._change) return;
- const hasComment = (path: string) => {
- return (
- this._changeComments?.getCommentsForPath(path, this._patchRange!)
- ?.length ?? 0 > 0
- );
- };
+ const hasComment = (path: string) =>
+ this._changeComments?.getCommentsForPath(path, this._patchRange!)
+ ?.length ?? 0 > 0;
const filesWithComments = this._fileList.filter(
file => file === this._path || hasComment(file)
);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
index bfb0cd8..30c6f49 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
@@ -302,9 +302,7 @@
items="[[_computeDownloadDropdownLinks(_change.project, _changeNum, _patchRange, _path, _diff)]]"
horizontal-align="left"
>
- <span class="downloadTitle">
- Download
- </span>
+ <span class="downloadTitle"> Download </span>
</gr-dropdown>
</span>
</div>
@@ -427,7 +425,8 @@
</gr-diff-preferences-dialog>
<gr-diff-cursor
id="cursor"
- on-navigate-to-next-unreviewed-file="_handleNextUnreviewedFile"
+ on-navigate-to-next-unreviewed-file="_navigateToNextUnreviewedFile"
+ on-navigate-to-previous-unreviewed-file="_navigateToPreviousUnreviewedFile"
on-navigate-to-next-file-with-comments="_navigateToNextFileWithCommentThread"
></gr-diff-cursor>
<gr-comment-api id="commentAPI"></gr-comment-api>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
index b5473a3..5c3dfdc 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
@@ -19,7 +19,7 @@
import './gr-diff-view.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {ChangeStatus} from '../../../constants/constants.js';
-import {TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
+import {TestKeyboardShortcutBinder, stubRestApi} from '../../../test/test-utils.js';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
import {ChangeComments, _testOnly_findCommentById, _testOnly_getCommentsForPath} from '../gr-comment-api/gr-comment-api.js';
import {GerritView} from '../../../services/router/router-model.js';
@@ -28,7 +28,6 @@
createRevisions,
createComment,
} from '../../../test/test-data-generators.js';
-import {stubRestApi} from '../../../test/test-utils.js';
import {EditPatchSetNum} from '../../../types/common.js';
const basicFixture = fixtureFromElement('gr-diff-view');
@@ -624,6 +623,76 @@
assert.isNotOk(args[3]);
});
+ test('A fires an error event when not logged in', done => {
+ const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
+ sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
+ const loggedInErrorSpy = sinon.spy();
+ element.addEventListener('show-auth-required', loggedInErrorSpy);
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ flush(() => {
+ assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
+ 'should only work when the user is logged in.');
+ assert.isNull(window.sessionStorage.getItem(
+ 'changeView.showReplyDialog'));
+ assert.isTrue(loggedInErrorSpy.called);
+ done();
+ });
+ });
+
+ test('A navigates to change with logged in', done => {
+ element._changeNum = '42';
+ element._patchRange = {
+ basePatchNum: 5,
+ patchNum: 10,
+ };
+ element._change = {
+ _number: 42,
+ revisions: {
+ a: {_number: 10, commit: {parents: []}},
+ b: {_number: 5, commit: {parents: []}},
+ },
+ };
+ const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
+ sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+ const loggedInErrorSpy = sinon.spy();
+ element.addEventListener('show-auth-required', loggedInErrorSpy);
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ flush(() => {
+ assert.isTrue(element.changeViewState.showReplyDialog);
+ assert(changeNavStub.lastCall.calledWithExactly(element._change, 10,
+ 5), 'Should navigate to /c/42/5..10');
+ assert.isFalse(loggedInErrorSpy.called);
+ done();
+ });
+ });
+
+ test('A navigates to change with old patch number with logged in', done => {
+ element._changeNum = '42';
+ element._patchRange = {
+ basePatchNum: PARENT,
+ patchNum: 1,
+ };
+ element._change = {
+ _number: 42,
+ revisions: {
+ a: {_number: 1, commit: {parents: []}},
+ b: {_number: 2, commit: {parents: []}},
+ },
+ };
+ const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
+ sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+ const loggedInErrorSpy = sinon.spy();
+ element.addEventListener('show-auth-required', loggedInErrorSpy);
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ flush(() => {
+ assert.isTrue(element.changeViewState.showReplyDialog);
+ assert(changeNavStub.lastCall.calledWithExactly(element._change, 1,
+ PARENT), 'Should navigate to /c/42/1');
+ assert.isFalse(loggedInErrorSpy.called);
+ done();
+ });
+ });
+
test('keyboard shortcuts with patch range', () => {
element._changeNum = '42';
element._patchRange = {
@@ -644,19 +713,6 @@
const diffNavStub = sinon.stub(GerritNav, 'navigateToDiff');
const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
- 'should only work when the user is logged in.');
- assert.isNull(window.sessionStorage.getItem(
- 'changeView.showReplyDialog'));
-
- element._loggedIn = true;
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- assert.isTrue(element.changeViewState.showReplyDialog);
-
- assert(changeNavStub.lastCall.calledWithExactly(element._change, 10,
- 5), 'Should navigate to /c/42/5..10');
-
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
assert(changeNavStub.lastCall.calledWithExactly(element._change, 10,
5), 'Should navigate to /c/42/5..10');
@@ -717,19 +773,6 @@
const diffNavStub = sinon.stub(GerritNav, 'navigateToDiff');
const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
- 'should only work when the user is logged in.');
- assert.isNull(window.sessionStorage.getItem(
- 'changeView.showReplyDialog'));
-
- element._loggedIn = true;
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- assert.isTrue(element.changeViewState.showReplyDialog);
-
- assert(changeNavStub.lastCall.calledWithExactly(element._change, 1,
- PARENT), 'Should navigate to /c/42/1');
-
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
assert(changeNavStub.lastCall.calledWithExactly(element._change, 1,
PARENT), 'Should navigate to /c/42/1');
@@ -1872,7 +1915,7 @@
'a/b/test.c': {},
};
stubRestApi('getConfig').returns(Promise.resolve({change: {}}));
- stubRestApi('getLoggedIn').returns(Promise.resolve(true));
+
stubRestApi('getProjectConfig').returns(Promise.resolve({}));
stubRestApi('getDiffChangeDetail').returns(Promise.resolve({}));
stubRestApi('getChangeFiles').returns(Promise.resolve(changedFiles));
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
index 6974a76..41dd159 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
@@ -22,11 +22,9 @@
import '../gr-diff-selection/gr-diff-selection';
import '../gr-syntax-themes/gr-syntax-theme';
import '../gr-ranged-comment-themes/gr-ranged-comment-theme';
-import '../gr-ranged-comment-chip/gr-ranged-comment-chip';
+import '../gr-ranged-comment-hint/gr-ranged-comment-hint';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {htmlTemplate} from './gr-diff_html';
import {LineNumber} from './gr-diff-line';
import {
@@ -74,8 +72,10 @@
CreateCommentEventDetail as CreateCommentEventDetailApi,
RenderPreferences,
} from '../../../api/diff';
-import {isSafari} from '../../../utils/dom-util';
+import {isSafari, toggleClass} from '../../../utils/dom-util';
import {assertIsDefined} from '../../../utils/common-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {DiffContextExpandedEventDetail} from '../gr-diff-builder/gr-diff-builder';
const NO_NEWLINE_BASE = 'No newline at end of base file.';
const NO_NEWLINE_REVISION = 'No newline at end of revision file.';
@@ -93,8 +93,6 @@
*/
const COMMIT_MSG_LINE_LENGTH = 72;
-const RENDER_DIFF_TABLE_DEBOUNCE_NAME = 'renderDiffTable';
-
export interface LineOfInterest {
number: number;
leftSide: boolean;
@@ -113,9 +111,7 @@
}
@customElement('gr-diff')
-export class GrDiff extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiff extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -257,6 +253,9 @@
@property({type: Boolean})
showNewlineWarningRight = false;
+ @property({type: String, observer: '_useNewImageDiffUiObserver'})
+ useNewImageDiffUi = false;
+
@property({
type: String,
computed:
@@ -286,9 +285,13 @@
@property({type: Array})
layers?: DiffLayer[];
- /** @override */
- created() {
- super.created();
+ @property({type: Boolean})
+ isAttached = false;
+
+ private renderDiffTableTask?: DelayedTask;
+
+ constructor() {
+ super();
this._setLoading(true);
this.addEventListener('create-range-comment', (e: Event) =>
this._handleCreateRangeComment(e as CustomEvent)
@@ -298,17 +301,19 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._observeNodes();
+ this.isAttached = true;
}
/** @override */
- detached() {
- this.cancelDebouncer(RENDER_DIFF_TABLE_DEBOUNCE_NAME);
- super.detached();
+ disconnectedCallback() {
+ this.isAttached = false;
+ this.renderDiffTableTask?.cancel();
this._unobserveIncrementalNodes();
this._unobserveNodes();
+ super.disconnectedCallback();
}
showNoChangeMessage(
@@ -328,44 +333,37 @@
}
@observe('loggedIn', 'isAttached')
- _enableSelectionObserver(loggedIn: boolean, isAttached?: boolean) {
- // Polymer 2: check for undefined
- if ([loggedIn, isAttached].includes(undefined)) {
- return;
- }
-
+ _enableSelectionObserver(loggedIn: boolean, isAttached: boolean) {
if (loggedIn && isAttached) {
- this.listen(
- document,
+ document.addEventListener(
'-shadow-selectionchange',
- '_handleSelectionChange'
+ this.handleSelectionChange
);
- this.listen(document, 'mouseup', '_handleMouseUp');
+ document.addEventListener('mouseup', this.handleMouseUp);
} else {
- this.unlisten(
- document,
+ document.removeEventListener(
'-shadow-selectionchange',
- '_handleSelectionChange'
+ this.handleSelectionChange
);
- this.unlisten(document, 'mouseup', '_handleMouseUp');
+ document.removeEventListener('mouseup', this.handleMouseUp);
}
}
- _handleSelectionChange() {
+ private readonly handleSelectionChange = () => {
// Because of shadow DOM selections, we handle the selectionchange here,
// and pass the shadow DOM selection into gr-diff-highlight, where the
// corresponding range is determined and normalized.
const selection = this._getShadowOrDocumentSelection();
this.$.highlights.handleSelectionChange(selection, false);
- }
+ };
- _handleMouseUp() {
+ private readonly handleMouseUp = () => {
// To handle double-click outside of text creating comments, we check on
// mouse-up if there's a selection that just covers a line change. We
// can't do that on selection change since the user may still be dragging.
const selection = this._getShadowOrDocumentSelection();
this.$.highlights.handleSelectionChange(selection, true);
- }
+ };
/** Gets the current selection, preferring the shadow DOM selection. */
_getShadowOrDocumentSelection() {
@@ -480,7 +478,7 @@
/** Cancel any remaining diff builder rendering work. */
cancel() {
this.$.diffBuilder.cancel();
- this.cancelDebouncer(RENDER_DIFF_TABLE_DEBOUNCE_NAME);
+ this.renderDiffTableTask?.cancel();
}
getCursorStops(): Array<HTMLElement | AbortStop> {
@@ -502,7 +500,7 @@
}
toggleLeftDiff() {
- this.toggleClass('no-left');
+ toggleClass(this, 'no-left');
}
_blameChanged(newValue?: BlameInfo[] | null) {
@@ -529,21 +527,15 @@
return classes.join(' ');
}
+ _handleDiffContextExpanded(e: CustomEvent<DiffContextExpandedEventDetail>) {
+ // Don't stop propagation. The host may listen for reporting or resizing.
+ this.$.diffBuilder.showContext(e.detail.groups, e.detail.section);
+ }
+
_handleTap(e: CustomEvent) {
const el = (dom(e) as EventApi).localTarget as Element;
- if (el.classList.contains('showContext')) {
- this.dispatchEvent(
- new CustomEvent('diff-context-expanded', {
- detail: {
- numLines: e.detail.numLines,
- },
- composed: true,
- bubbles: true,
- })
- );
- this.$.diffBuilder.showContext(e.detail.groups, e.detail.section);
- } else if (
+ if (
el.getAttribute('data-value') !== 'LOST' &&
(el.classList.contains('lineNum') ||
el.classList.contains('lineNumButton'))
@@ -716,6 +708,10 @@
this._prefsChanged(this.prefs);
}
+ _useNewImageDiffUiObserver() {
+ this._prefsChanged(this.prefs);
+ }
+
_prefsChanged(prefs?: DiffPreferencesInfo) {
if (!prefs) return;
@@ -755,7 +751,10 @@
this.classList.add('no-left');
}
if (renderPrefs.disable_context_control_buttons) {
- this.updateStyles({'--context-control-display': 'none'});
+ this.classList.add('disable-context-control-buttons');
+ }
+ if (renderPrefs.hide_line_length_indicator) {
+ this.classList.add('hide-line-length-indicator');
}
}
@@ -779,7 +778,7 @@
* render once.
*/
_debounceRenderDiffTable() {
- this.debounce(RENDER_DIFF_TABLE_DEBOUNCE_NAME, () =>
+ this.renderDiffTableTask = debounce(this.renderDiffTableTask, () =>
this._renderDiffTable()
);
}
@@ -804,19 +803,21 @@
const keyLocations = this._computeKeyLocations();
const bypassPrefs = this._getBypassPrefs(this.prefs);
- this.$.diffBuilder.render(keyLocations, bypassPrefs).then(() => {
- this.dispatchEvent(
- new CustomEvent('render', {
- bubbles: true,
- composed: true,
- detail: {contentRendered: true},
- })
- );
- });
+ this.$.diffBuilder
+ .render(keyLocations, bypassPrefs, this.renderPrefs)
+ .then(() => {
+ this.dispatchEvent(
+ new CustomEvent('render', {
+ bubbles: true,
+ composed: true,
+ detail: {contentRendered: true},
+ })
+ );
+ });
}
_handleRenderContent() {
- this.querySelectorAll('gr-ranged-comment-chip').forEach(element =>
+ this.querySelectorAll('gr-ranged-comment-hint').forEach(element =>
element.remove()
);
this._setLoading(false);
@@ -864,14 +865,14 @@
const slotAtt = threadEl.getAttribute('slot');
if (range && isLongCommentRange(range) && slotAtt) {
- const longRangeCommentChip = document.createElement(
- 'gr-ranged-comment-chip'
+ const longRangeCommentHint = document.createElement(
+ 'gr-ranged-comment-hint'
);
- longRangeCommentChip.range = range;
- longRangeCommentChip.setAttribute('threadElRootId', threadEl.rootId);
- longRangeCommentChip.setAttribute('slot', slotAtt);
- this.insertBefore(longRangeCommentChip, threadEl);
- this._redispatchHoverEvents(longRangeCommentChip, threadEl);
+ longRangeCommentHint.range = range;
+ longRangeCommentHint.setAttribute('threadElRootId', threadEl.rootId);
+ longRangeCommentHint.setAttribute('slot', slotAtt);
+ this.insertBefore(longRangeCommentHint, threadEl);
+ this._redispatchHoverEvents(longRangeCommentHint, threadEl);
}
// Create a slot for the thread and attach it to the thread group.
@@ -896,7 +897,7 @@
const removedThreadEls = info.removedNodes.filter(isThreadEl);
for (const threadEl of removedThreadEls) {
this.querySelector(
- `gr-ranged-comment-chip[threadElRootId="${threadEl.rootId}"]`
+ `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
)?.remove();
}
});
@@ -905,7 +906,7 @@
_portedCommentsWithoutRangeMessage() {
const div = document.createElement('div');
const icon = document.createElement('iron-icon');
- icon.setAttribute('icon', 'gr-icons:info');
+ icon.setAttribute('icon', 'gr-icons:info-outline');
div.appendChild(icon);
const span = document.createElement('span');
span.innerText = 'Original comment position not found in this patchset';
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
index 4d0e566..a93d5b5 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
@@ -24,6 +24,16 @@
:host(.no-left) .sideBySide .right:not([data-value]) + td {
display: none;
}
+ :host(.disable-context-control-buttons) {
+ --context-control-display: none;
+ }
+ :host(.disable-context-control-buttons) .section {
+ border-right: none;
+ }
+ :host(.hide-line-length-indicator) .full-width td.content .contentText {
+ background-image: none;
+ }
+
:host {
font-family: var(--monospace-font-family, ''), 'Roboto Mono';
font-size: var(--font-size, var(--font-size-code, 12px));
@@ -94,6 +104,12 @@
.lineNumButton:focus {
outline: none;
}
+ gr-image-viewer {
+ width: 100%;
+ height: 100%;
+ max-width: var(--image-viewer-max-width, 95vw);
+ max-height: var(--image-viewer-max-height, 90vh);
+ }
.image-diff .gr-diff {
text-align: center;
}
@@ -223,25 +239,22 @@
}
.delta.dueToMove .movedIn .moveDescription {
- color: var(--diff-moved-in-background);
- background-color: var(--diff-moved-in-label-background);
+ color: var(--diff-moved-in-label-color);
}
.delta.dueToMove .movedOut .moveDescription {
- color: var(--diff-moved-out-background);
- background-color: var(--diff-moved-out-label-background);
+ color: var(--diff-moved-out-label-color);
}
.moveLabel {
- display: flex;
- justify-content: flex-end;
font-family: var(--font-family, ''), 'Roboto Mono';
font-size: var(--font-size-small, 12px);
- }
- .delta.dueToMove .moveDescription {
- border-radius: var(--fully-rounded-radius, 1000px);
+ font-weight: var(--code-hint-font-weight, 500);
+ line-height: var(--line-height-small, 16px);
padding: var(--spacing-s) var(--spacing-m);
margin: var(--spacing-s);
- line-height: var(--line-height-small, 16px);
+ }
+ .delta.dueToMove .moveDescription {
display: flex;
+ justify-content: flex-end;
}
.moveDescription iron-icon {
@@ -339,9 +352,16 @@
transform: translateY(-50%);
--gr-button: {
color: var(--diff-context-control-color);
- border: solid var(--border-color);
- border-width: 1px;
- border-radius: var(--border-radius);
+ border-style: solid;
+ border-color: var(--border-color);
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-left-radius: var(--border-radius);
+ border-top-right-radius: var(--border-radius);
+ border-bottom-right-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
padding: var(--spacing-s) var(--spacing-l);
}
}
@@ -359,9 +379,16 @@
transform: translateY(-100%);
--gr-button: {
color: var(--diff-context-control-color);
- border: solid var(--border-color);
- border-width: 1px 1px 0 1px;
- border-radius: var(--border-radius) var(--border-radius) 0 0;
+ border-style: solid;
+ border-color: var(--border-color);
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 0;
+ border-left-width: 1px;
+ border-top-left-radius: var(--border-radius);
+ border-top-right-radius: var(--border-radius);
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
padding: var(--spacing-xxs) var(--spacing-l);
}
}
@@ -370,9 +397,16 @@
top: calc(100% + var(--divider-border));
--gr-button: {
color: var(--diff-context-control-color);
- border: solid var(--border-color);
- border-width: 0 1px 1px 1px;
- border-radius: 0 0 var(--border-radius) var(--border-radius);
+ border-style: solid;
+ border-color: var(--border-color);
+ border-top-width: 0;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
padding: var(--spacing-xxs) var(--spacing-l);
}
}
@@ -393,6 +427,15 @@
content: '\\00BB';
position: absolute;
}
+ .special-char-indicator {
+ /* spacing so elements don't collide */
+ padding-right: var(--spacing-m);
+ }
+ .special-char-indicator:before {
+ color: var(--diff-tab-indicator-color);
+ content: '•';
+ position: absolute;
+ }
/* Is defined after other background-colors, such that this
rule wins in case of same specificity. */
.trailing-whitespace,
@@ -429,11 +472,17 @@
background: var(--diff-selection-background-color);
}
td.lost div {
- background-color: var(--blue-50);
- padding: var(--spacing-s);
+ background-color: var(--info-background);
+ padding: var(--spacing-s) 0 0 0;
+ }
+ td.lost div:first-of-type {
+ font-family: var(--font-family, 'Roboto');
+ font-size: var(--font-size-normal, 14px);
+ line-height: var(--line-height-normal);
}
td.lost iron-icon {
- margin-right: var(--spacing-s);
+ padding: 0 var(--spacing-s) 0 var(--spacing-m);
+ color: var(--blue-700);
}
col.blame {
display: none;
@@ -466,8 +515,7 @@
}
/** Support the line length indicator **/
.full-width td.content .contentText {
- /* Base 64 encoded 1x1px of #ddd */
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO8+x8AAr8B3gzOjaQAAAAASUVORK5CYII=');
+ background-image: var(--line-length-indicator);
background-position: var(--line-limit) 0;
background-repeat: repeat-y;
}
@@ -571,7 +619,8 @@
</div>
<div
class$="[[_computeContainerClass(loggedIn, viewMode, displayLine)]]"
- on-tap="_handleTap"
+ on-click="_handleTap"
+ on-diff-context-expanded="_handleDiffContextExpanded"
>
<gr-diff-selection diff="[[diff]]">
<gr-diff-highlight
@@ -592,6 +641,7 @@
base-image="[[baseImage]]"
layers="[[layers]]"
revision-image="[[revisionImage]]"
+ use-new-image-diff-ui="[[useNewImageDiffUi]]"
>
<table
id="diffTable"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
index 49eac72..86946a6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
@@ -52,15 +52,17 @@
sinon.stub(element.$.highlights, 'handleSelectionChange');
});
- test('enabled if logged in', () => {
+ test('enabled if logged in', async () => {
element.loggedIn = true;
emulateSelection();
+ await flush();
assert.isTrue(element.$.highlights.handleSelectionChange.called);
});
- test('ignored if logged out', () => {
+ test('ignored if logged out', async () => {
element.loggedIn = false;
emulateSelection();
+ await flush();
assert.isFalse(element.$.highlights.handleSelectionChange.called);
});
});
@@ -206,7 +208,7 @@
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile1.body);
+ 'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
leftLoaded = true;
if (rightLoaded) {
@@ -218,7 +220,7 @@
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile2.body);
+ 'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
rightLoaded = true;
@@ -300,7 +302,7 @@
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile1.body);
+ 'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
leftLoaded = true;
if (rightLoaded) {
@@ -312,7 +314,7 @@
rightImage.addEventListener('load', () => {
assert.isOk(rightImage);
assert.equal(rightImage.getAttribute('src'),
- 'data:image/bmp;base64, ' + mockFile2.body);
+ 'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
rightLoaded = true;
@@ -460,7 +462,7 @@
const el = document.createElement('div');
el.className = 'showContext';
el.addEventListener('click', e => {
- element._handleTap(e);
+ element._handleDiffContextExpanded(e);
assert.isTrue(showContextStub.called);
done();
});
@@ -555,7 +557,7 @@
.calledWithExactly(fakeLineEl, 42));
});
- test('adds long range comment chip', async () => {
+ test('adds long range comment hint', async () => {
const range = {
start_line: 1,
end_line: 12,
@@ -580,10 +582,10 @@
await flush();
assert.deepEqual(
- element.querySelector('gr-ranged-comment-chip').range, range);
+ element.querySelector('gr-ranged-comment-hint').range, range);
});
- test('no duplicate range chip for same thread', async () => {
+ test('no duplicate range hint for same thread', async () => {
const range = {
start_line: 1,
end_line: 12,
@@ -596,10 +598,10 @@
threadEl.setAttribute('line-num', 1);
threadEl.setAttribute('range', JSON.stringify(range));
threadEl.setAttribute('slot', 'right-1');
- const firstChip = document.createElement('gr-ranged-comment-chip');
- firstChip.range = range;
- firstChip.setAttribute('threadElRootId', threadEl.rootId);
- firstChip.setAttribute('slot', 'right-1');
+ const firstHint = document.createElement('gr-ranged-comment-hint');
+ firstHint.range = range;
+ firstHint.setAttribute('threadElRootId', threadEl.rootId);
+ firstHint.setAttribute('slot', 'right-1');
const content = [{
a: [],
b: [],
@@ -608,7 +610,7 @@
}];
setupSampleDiff({content});
- element.appendChild(firstChip);
+ element.appendChild(firstHint);
await flush();
element._handleRenderContent();
await flush();
@@ -616,10 +618,10 @@
await flush();
assert.equal(
- element.querySelectorAll('gr-ranged-comment-chip').length, 1);
+ element.querySelectorAll('gr-ranged-comment-hint').length, 1);
});
- test('removes long range comment chip when comment is discarded',
+ test('removes long range comment hint when comment is discarded',
async () => {
const range = {
start_line: 1,
@@ -646,7 +648,7 @@
threadEl.remove();
await flush();
- assert.isEmpty(element.querySelectorAll('gr-ranged-comment-chip'));
+ assert.isEmpty(element.querySelectorAll('gr-ranged-comment-hint'));
});
suite('change in preferences', () => {
@@ -660,14 +662,14 @@
change_type: 'MODIFIED',
content: [{skip: 66}],
};
- element.flushDebouncer('renderDiffTable');
+ element.renderDiffTableTask.flush();
});
test('change in preferences re-renders diff', () => {
sinon.stub(element, '_renderDiffTable');
element.prefs = {
...MINIMAL_PREFS, time_format: 'HHMM_12'};
- element.flushDebouncer('renderDiffTable');
+ element.renderDiffTableTask.flush();
assert.isTrue(element._renderDiffTable.called);
});
@@ -676,14 +678,14 @@
const newPrefs1 = {...MINIMAL_PREFS,
line_wrapping: true};
element.prefs = newPrefs1;
- element.flushDebouncer('renderDiffTable');
+ element.renderDiffTableTask.flush();
assert.isTrue(element._renderDiffTable.called);
stub.reset();
const newPrefs2 = {...newPrefs1};
delete newPrefs2.line_wrapping;
element.prefs = newPrefs2;
- element.flushDebouncer('renderDiffTable');
+ element.renderDiffTableTask.flush();
assert.isTrue(element._renderDiffTable.called);
});
@@ -693,7 +695,7 @@
element.noRenderOnPrefsChange = true;
element.prefs = {
...MINIMAL_PREFS, time_format: 'HHMM_12'};
- element.flushDebouncer('renderDiffTable');
+ element.renderDiffTableTask.flush();
assert.isFalse(element._renderDiffTable.called);
});
});
@@ -804,7 +806,7 @@
assert.equal(element.prefs.context, 3);
assert.equal(element._safetyBypass, -1);
- assert.equal(renderStub.firstCall.lastArg.context, -1);
+ assert.equal(renderStub.firstCall.args[1].context, -1);
});
test('toggles collapse context from bypass', async () => {
@@ -817,7 +819,7 @@
assert.equal(element.prefs.context, 3);
assert.isNull(element._safetyBypass);
- assert.equal(renderStub.firstCall.lastArg.context, 3);
+ assert.equal(renderStub.firstCall.args[1].context, 3);
});
test('toggles collapse context from pref using default', async () => {
@@ -829,7 +831,7 @@
assert.equal(element.prefs.context, -1);
assert.equal(element._safetyBypass, 10);
- assert.equal(renderStub.firstCall.lastArg.context, 10);
+ assert.equal(renderStub.firstCall.args[1].context, 10);
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
index 1ce2506..4b53269 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-dropdown-list/gr-dropdown-list';
import '../../shared/gr-select/gr-select';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-patch-range-select_html';
import {pluralize} from '../../../utils/string-util';
@@ -38,6 +36,7 @@
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
import {hasOwnProperty} from '../../../utils/common-util';
import {
+ BasePatchSetNum,
ParentPatchSetNum,
PatchSetNum,
RevisionInfo,
@@ -58,7 +57,7 @@
export interface PatchRangeChangeDetail {
patchNum?: PatchSetNum;
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
}
export type PatchRangeChangeEvent = CustomEvent<PatchRangeChangeDetail>;
@@ -81,12 +80,9 @@
*
* @property {string} patchNum
* @property {string} basePatchNum
- * @extends PolymerElement
*/
@customElement('gr-patch-range-select')
-export class GrPatchRangeSelect extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrPatchRangeSelect extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -123,7 +119,7 @@
patchNum?: PatchSetNum;
@property({type: String})
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
@property({type: Object})
revisions?: RevisionInfo[];
@@ -222,7 +218,7 @@
_computePatchDropdownContent(
availablePatches?: PatchSet[],
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
_sortedRevisions?: RevisionInfo[],
changeComments?: ChangeComments
): DropdownItem[] | undefined {
@@ -449,7 +445,7 @@
patchNum: patchSetValue,
}),
});
- detail.basePatchNum = patchSetValue;
+ detail.basePatchNum = patchSetValue as BasePatchSetNum;
}
this.dispatchEvent(
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
similarity index 83%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
index 6948283..3d35c26 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
@@ -17,11 +17,11 @@
import {customElement, property} from '@polymer/decorators';
import {CommentRange} from '../../../types/common';
-import {htmlTemplate} from './gr-ranged-comment-chip_html';
+import {htmlTemplate} from './gr-ranged-comment-hint_html';
import {PolymerElement} from '@polymer/polymer/polymer-element';
-@customElement('gr-ranged-comment-chip')
-export class GrRangedCommentChip extends PolymerElement {
+@customElement('gr-ranged-comment-hint')
+export class GrRangedCommentHint extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -37,6 +37,6 @@
declare global {
interface HTMLElementTagNameMap {
- 'gr-ranged-comment-chip': GrRangedCommentChip;
+ 'gr-ranged-comment-hint': GrRangedCommentHint;
}
}
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
similarity index 74%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
index c2861fa..670bfd2 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_html.ts
@@ -22,31 +22,25 @@
</style>
<style include="shared-styles">
.row {
- color: var(--ranged-comment-chip-text-color);
+ color: var(--ranged-comment-hint-text-color);
display: flex;
font-family: var(--font-family, ''), 'Roboto Mono';
font-size: var(--font-size-small, 12px);
+ font-weight: var(--code-hint-font-weight, 500);
line-height: var(--line-height-small, 16px);
justify-content: flex-end;
margin: var(--spacing-xs) 0;
+ padding: var(--spacing-s) var(--spacing-l);
}
.icon {
- color: var(--ranged-comment-chip-text-color);
+ color: var(--ranged-comment-hint-text-color);
height: var(--line-height-small, 16px);
width: var(--line-height-small, 16px);
margin-right: var(--spacing-s);
}
- .chip {
- background-color: var(--ranged-comment-chip-background);
- border-radius: var(--fully-rounded-radius, 1000px);
- margin: var(--spacing-s);
- padding: var(--spacing-s) var(--spacing-m);
- }
</style>
<div class="row rangeHighlight">
- <div class="chip">
- <iron-icon class="icon" icon="gr-icons:comment-outline"></iron-icon>
- [[_computeRangeLabel(range)]]
- </div>
+ <iron-icon class="icon" icon="gr-icons:comment"></iron-icon>
+ [[_computeRangeLabel(range)]]
</div>
`;
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
similarity index 83%
rename from polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts
rename to polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
index 8bce99d..932c367 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-chip/gr-ranged-comment-chip_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint_test.ts
@@ -17,13 +17,13 @@
import '../../../test/common-test-setup-karma';
import {CommentRange} from '../../../types/common';
-import {GrRangedCommentChip} from './gr-ranged-comment-chip';
+import {GrRangedCommentHint} from './gr-ranged-comment-hint';
-suite('gr-ranged-comment-chip tests', () => {
- let element: GrRangedCommentChip;
+suite('gr-ranged-comment-hint tests', () => {
+ let element: GrRangedCommentHint;
setup(() => {
- element = fixtureFromElement('gr-ranged-comment-chip').instantiate();
+ element = fixtureFromElement('gr-ranged-comment-hint').instantiate();
});
test('shows line range', async () => {
@@ -34,7 +34,7 @@
end_character: 3,
} as CommentRange;
await flush();
- const textDiv = element.root!.querySelector<HTMLDivElement>('.chip');
+ const textDiv = element.root!.querySelector<HTMLDivElement>('.row');
assert.equal(textDiv!.innerText.trim(), 'Long comment range 2 - 5');
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
index f33c2ce..11712dc 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-ranged-comment-layer_html';
import {GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line';
@@ -72,9 +70,7 @@
const HOVER_HIGHLIGHT = 'style-scope gr-diff range rangeHoverHighlight';
@customElement('gr-ranged-comment-layer')
-export class GrRangedCommentLayer
- extends GestureEventListeners(LegacyElementMixin(PolymerElement))
- implements DiffLayer {
+export class GrRangedCommentLayer extends PolymerElement implements DiffLayer {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
index ee52ab6..3b026b3 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.ts
@@ -18,8 +18,6 @@
import {GrTooltip} from '../../shared/gr-tooltip/gr-tooltip';
import {customElement, property} from '@polymer/decorators';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-selection-action-box_html';
import {fireEvent} from '../../../utils/event-util';
@@ -37,9 +35,7 @@
}
@customElement('gr-selection-action-box')
-export class GrSelectionActionBox extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrSelectionActionBox extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -56,10 +52,8 @@
@property({type: Boolean})
positionBelow = false;
- /** @override */
- created() {
- super.created();
-
+ constructor() {
+ super();
// See https://crbug.com/gerrit/4767
this.addEventListener('mousedown', e => this._handleMouseDown(e));
}
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
index 1150674..081d28d 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
@@ -15,13 +15,8 @@
* limitations under the License.
*/
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
import {FILE, GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line';
import {CancelablePromise, util} from '../../../scripts/util';
-import {customElement, property} from '@polymer/decorators';
import {DiffFileMetaInfo, DiffInfo} from '../../../types/diff';
import {DiffLayer, DiffLayerListener, HighlightJS} from '../../../types/types';
import {GrLibLoader} from '../../shared/gr-lib-loader/gr-lib-loader';
@@ -158,52 +153,46 @@
lastNotify: {left: number; right: number};
}
-@customElement('gr-syntax-layer')
-export class GrSyntaxLayer
- extends GestureEventListeners(LegacyElementMixin(PolymerElement))
- implements DiffLayer {
- static get template() {
- return html``;
- }
-
- @property({type: Object, observer: '_diffChanged'})
+export class GrSyntaxLayer implements DiffLayer {
diff?: DiffInfo;
- @property({type: Boolean})
enabled = true;
- @property({type: Array})
- _baseRanges: SyntaxLayerRange[][] = [];
+ private baseRanges: SyntaxLayerRange[][] = [];
- @property({type: Array})
- _revisionRanges: SyntaxLayerRange[][] = [];
+ private revisionRanges: SyntaxLayerRange[][] = [];
- @property({type: String})
- _baseLanguage?: string;
+ private baseLanguage?: string;
- @property({type: String})
- _revisionLanguage?: string;
+ private revisionLanguage?: string;
- @property({type: Array})
- _listeners: DiffLayerListener[] = [];
+ private listeners: DiffLayerListener[] = [];
- @property({type: Number})
- _processHandle: number | null = null;
+ private processHandle: number | null = null;
- @property({type: Object})
- _processPromise: CancelablePromise<unknown> | null = null;
+ private processPromise: CancelablePromise<unknown> | null = null;
- @property({type: Object})
- _hljs?: HighlightJS;
+ private hljs?: HighlightJS;
private readonly libLoader = new GrLibLoader();
+ init(diff?: DiffInfo) {
+ this.cancel();
+ this.baseRanges = [];
+ this.revisionRanges = [];
+ this.diff = diff;
+ }
+
+ setEnabled(enabled: boolean) {
+ this.enabled = enabled;
+ }
+
addListener(listener: DiffLayerListener) {
- this.push('_listeners', listener);
+ this.listeners.push(listener);
}
removeListener(listener: DiffLayerListener) {
- this._listeners = this._listeners.filter(f => f !== listener);
+ this.listeners = this.listeners.filter(f => f !== listener);
}
/**
@@ -231,13 +220,13 @@
// Find the relevant syntax ranges, if any.
let ranges: SyntaxLayerRange[] = [];
- if (side === 'left' && this._baseRanges.length >= line.beforeNumber) {
- ranges = this._baseRanges[line.beforeNumber - 1] || [];
+ if (side === 'left' && this.baseRanges.length >= line.beforeNumber) {
+ ranges = this.baseRanges[line.beforeNumber - 1] || [];
} else if (
side === 'right' &&
- this._revisionRanges.length >= line.afterNumber
+ this.revisionRanges.length >= line.afterNumber
) {
- ranges = this._revisionRanges[line.afterNumber - 1] || [];
+ ranges = this.revisionRanges[line.afterNumber - 1] || [];
}
// Apply the ranges to the element.
@@ -263,24 +252,24 @@
*/
process() {
// Cancel any still running process() calls, because they append to the
- // same _baseRanges and _revisionRanges fields.
+ // same baseRanges and revisionRanges fields.
this.cancel();
// Discard existing ranges.
- this._baseRanges = [];
- this._revisionRanges = [];
+ this.baseRanges = [];
+ this.revisionRanges = [];
if (!this.enabled || !this.diff?.content.length) {
return Promise.resolve();
}
if (this.diff.meta_a) {
- this._baseLanguage = this._getLanguage(this.diff.meta_a);
+ this.baseLanguage = this._getLanguage(this.diff.meta_a);
}
if (this.diff.meta_b) {
- this._revisionLanguage = this._getLanguage(this.diff.meta_b);
+ this.revisionLanguage = this._getLanguage(this.diff.meta_b);
}
- if (!this._baseLanguage && !this._revisionLanguage) {
+ if (!this.baseLanguage && !this.revisionLanguage) {
return Promise.resolve();
}
@@ -295,12 +284,12 @@
const rangesCache = new Map<string, SyntaxLayerRange[]>();
- this._processPromise = util.makeCancelable(
+ this.processPromise = util.makeCancelable(
this._loadHLJS().then(
() =>
new Promise<void>(resolve => {
const nextStep = () => {
- this._processHandle = null;
+ this.processHandle = null;
this._processNextLine(state, rangesCache);
// Move to the next line in the section.
@@ -324,18 +313,18 @@
if (state.lineIndex % 100 === 0) {
this._notify(state);
- this._processHandle = this.async(nextStep, ASYNC_DELAY);
+ this.processHandle = window.setTimeout(nextStep, ASYNC_DELAY);
} else {
nextStep.call(this);
}
};
- this._processHandle = this.async(nextStep, 1);
+ this.processHandle = window.setTimeout(nextStep, 1);
})
)
);
- return this._processPromise.finally(() => {
- this._processPromise = null;
+ return this.processPromise.finally(() => {
+ this.processPromise = null;
});
}
@@ -343,21 +332,15 @@
* Cancel any asynchronous syntax processing jobs.
*/
cancel() {
- if (this._processHandle !== null) {
- this.cancelAsync(this._processHandle);
- this._processHandle = null;
+ if (this.processHandle !== null) {
+ clearTimeout(this.processHandle);
+ this.processHandle = null;
}
- if (this._processPromise) {
- this._processPromise.cancel();
+ if (this.processPromise) {
+ this.processPromise.cancel();
}
}
- _diffChanged() {
- this.cancel();
- this._baseRanges = [];
- this._revisionRanges = [];
- }
-
/**
* Take a string of HTML with the (potentially nested) syntax markers
* Highlight.js emits and emit a list of text ranges and classes for the
@@ -420,7 +403,7 @@
rangesCache: Map<string, SyntaxLayerRange[]>
) {
if (!this.diff) return;
- if (!this._hljs) return;
+ if (!this.hljs) return;
let baseLine;
let revisionLine;
@@ -439,44 +422,45 @@
revisionLine = section.b[state.lineIndex];
state.lineNums.right++;
}
+ if (section.skip) {
+ state.lineNums.left += section.skip;
+ state.lineNums.right += section.skip;
+ for (let i = 0; i < section.skip; i++) this.revisionRanges.push([]);
+ }
}
// To store the result of the syntax highlighter.
let result;
if (
- this._baseLanguage &&
+ this.baseLanguage &&
baseLine !== undefined &&
- this._hljs.getLanguage(this._baseLanguage)
+ this.hljs.getLanguage(this.baseLanguage)
) {
- baseLine = this._workaround(this._baseLanguage, baseLine);
- result = this._hljs.highlight(
- this._baseLanguage,
+ baseLine = this._workaround(this.baseLanguage, baseLine);
+ result = this.hljs.highlight(
+ this.baseLanguage,
baseLine,
true,
state.baseContext
);
- this.push(
- '_baseRanges',
- this._rangesFromString(result.value, rangesCache)
- );
+ this.baseRanges.push(this._rangesFromString(result.value, rangesCache));
state.baseContext = result.top;
}
if (
- this._revisionLanguage &&
+ this.revisionLanguage &&
revisionLine !== undefined &&
- this._hljs.getLanguage(this._revisionLanguage)
+ this.hljs.getLanguage(this.revisionLanguage)
) {
- revisionLine = this._workaround(this._revisionLanguage, revisionLine);
- result = this._hljs.highlight(
- this._revisionLanguage,
+ revisionLine = this._workaround(this.revisionLanguage, revisionLine);
+ result = this.hljs.highlight(
+ this.revisionLanguage,
revisionLine,
true,
state.revisionContext
);
- this.push(
- '_revisionRanges',
+ this.revisionRanges.push(
this._rangesFromString(result.value, rangesCache)
);
state.revisionContext = result.top;
@@ -586,20 +570,14 @@
}
_notifyRange(start: number, end: number, side: Side) {
- for (const listener of this._listeners) {
+ for (const listener of this.listeners) {
listener(start, end, side);
}
}
_loadHLJS() {
return this.libLoader.getHLJS().then(hljs => {
- this._hljs = hljs;
+ this.hljs = hljs;
});
}
}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-syntax-layer': GrSyntaxLayer;
- }
-}
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
index 20106d8..f9100a2 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
@@ -20,8 +20,7 @@
import './gr-syntax-layer.js';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation.js';
import {GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line.js';
-
-const basicFixture = fixtureFromElement('gr-syntax-layer');
+import {GrSyntaxLayer} from './gr-syntax-layer.js';
suite('gr-syntax-layer tests', () => {
let diff;
@@ -48,7 +47,7 @@
}
setup(() => {
- element = basicFixture.instantiate();
+ element = new GrSyntaxLayer();
diff = getMockDiffResponse();
element.diff = diff;
});
@@ -76,7 +75,7 @@
el.textContent = str;
const line = new GrDiffLine(GrDiffLineType.REMOVE);
line.beforeNumber = 12;
- element._baseRanges[11] = [{
+ element.baseRanges[11] = [{
start,
length,
className,
@@ -103,7 +102,7 @@
el.textContent = str;
const line = new GrDiffLine(GrDiffLineType.REMOVE);
line.beforeNumber = 12;
- element._baseRanges[11] = [{
+ element.baseRanges[11] = [{
start,
length,
className,
@@ -127,8 +126,8 @@
processPromise.then(() => {
assert.isFalse(processNextSpy.called);
- assert.equal(element._baseRanges.length, 0);
- assert.equal(element._revisionRanges.length, 0);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
done();
});
});
@@ -145,8 +144,8 @@
processPromise.then(() => {
assert.isFalse(processNextSpy.called);
- assert.equal(element._baseRanges.length, 0);
- assert.equal(element._revisionRanges.length, 0);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
done();
});
});
@@ -160,8 +159,8 @@
processPromise.then(() => {
assert.isFalse(processNextSpy.called);
- assert.equal(element._baseRanges.length, 0);
- assert.equal(element._revisionRanges.length, 0);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
assert.isFalse(loadHLJSSpy.called);
done();
});
@@ -183,13 +182,13 @@
const linesB = diff.meta_b.lines;
assert.isTrue(processNextSpy.called);
- assert.equal(element._baseRanges.length, linesA);
- assert.equal(element._revisionRanges.length, linesB);
+ assert.equal(element.baseRanges.length, linesA);
+ assert.equal(element.revisionRanges.length, linesB);
assert.equal(highlightSpy.callCount, linesA + linesB);
// The first line of both sides have a range.
- let ranges = [element._baseRanges[0], element._revisionRanges[0]];
+ let ranges = [element.baseRanges[0], element.revisionRanges[0]];
for (const range of ranges) {
assert.equal(range.length, 1);
assert.equal(range[0].className,
@@ -200,8 +199,8 @@
// There are no ranges from ll.1-12 on the left and ll.1-11 on the
// right.
- ranges = element._baseRanges.slice(1, 12)
- .concat(element._revisionRanges.slice(1, 11));
+ ranges = element.baseRanges.slice(1, 12)
+ .concat(element.revisionRanges.slice(1, 11));
for (const range of ranges) {
assert.equal(range.length, 0);
@@ -209,7 +208,7 @@
// There should be another pair of ranges on l.13 for the left and
// l.12 for the right.
- ranges = [element._baseRanges[13], element._revisionRanges[12]];
+ ranges = [element.baseRanges[13], element.revisionRanges[12]];
for (const range of ranges) {
assert.equal(range.length, 1);
@@ -221,13 +220,13 @@
// The next group should have a similar instance on either side.
- let range = element._baseRanges[15];
+ let range = element.baseRanges[15];
assert.equal(range.length, 1);
assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
assert.equal(range[0].start, 34);
assert.equal(range[0].length, 'ipsum'.length);
- range = element._revisionRanges[14];
+ range = element.revisionRanges[14];
assert.equal(range.length, 1);
assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
assert.equal(range[0].start, 35);
@@ -237,9 +236,9 @@
});
});
- test('_diffChanged calls cancel', () => {
- const cancelSpy = sinon.spy(element, '_diffChanged');
- element.diff = {content: []};
+ test('init calls cancel', () => {
+ const cancelSpy = sinon.spy(element, 'cancel');
+ element.init({content: []});
assert.isTrue(cancelSpy.called);
});
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
index 7df3d75..7e4edd6 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
@@ -17,8 +17,6 @@
import '../../../styles/gr-table-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-list-view/gr-list-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-documentation-search_html';
import {
@@ -32,9 +30,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-documentation-search')
-export class GrDocumentationSearch extends ListViewMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrDocumentationSearch extends ListViewMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -57,8 +53,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
fireTitleChange(this, 'Documentation Search');
}
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
index 4c63303..2828918 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-default-editor_html';
import {customElement, property} from '@polymer/decorators';
@@ -32,10 +30,7 @@
}
@customElement('gr-default-editor')
-/** @extends PolymerElement */
-export class GrDefaultEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDefaultEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
index bc153ee..77eccca 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
@@ -22,8 +22,6 @@
import '../../shared/gr-overlay/gr-overlay';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-edit-controls_html';
import {GrEditAction, GrEditConstants} from '../gr-edit-constants';
@@ -49,9 +47,7 @@
}
@customElement('gr-edit-controls')
-export class GrEditControls extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEditControls extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -167,16 +163,16 @@
if (autocomplete) {
autocomplete.focus();
}
- this.async(() => {
+ setTimeout(() => {
this.$.overlay.center();
}, 1);
});
}
_hideAllDialogs() {
- const dialogs = this.root!.querySelectorAll('.dialog') as NodeListOf<
- GrDialog
- >;
+ const dialogs = this.root!.querySelectorAll(
+ '.dialog'
+ ) as NodeListOf<GrDialog>;
for (const dialog of dialogs) {
this._closeDialog(dialog);
}
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
index 9f3d1bc..d2e1d64 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
@@ -17,8 +17,6 @@
import '../../shared/gr-button/gr-button';
import '../../shared/gr-dropdown/gr-dropdown';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-edit-file-controls_html';
import {GrEditConstants} from '../gr-edit-constants';
@@ -29,11 +27,8 @@
id: string;
}
-/** @extends PolymerElement */
@customElement('gr-edit-file-controls')
-class GrEditFileControls extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrEditFileControls extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 1e08a5c..fb8c2e0 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -18,11 +18,8 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-editable-label/gr-editable-label';
-import '../../shared/gr-storage/gr-storage';
import '../gr-default-editor/gr-default-editor';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-editor-view_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -40,12 +37,12 @@
NumericChangeId,
EditPatchSetNum,
} from '../../../types/common';
-import {GrStorage} from '../../shared/gr-storage/gr-storage';
import {HttpMethod, NotifyType} from '../../../constants/constants';
import {fireAlert, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
import {assertIsDefined} from '../../../utils/common-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
const RESTORED_MESSAGE = 'Content restored from a previous edit.';
const SAVING_MESSAGE = 'Saving changes...';
@@ -56,12 +53,8 @@
const STORAGE_DEBOUNCE_INTERVAL_MS = 100;
-const DEBOUNCER_STORE = 'store';
-
@customElement('gr-editor-view')
-export class GrEditorView extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrEditorView extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -122,7 +115,9 @@
private readonly restApiService = appContext.restApiService;
- private readonly storage = new GrStorage();
+ private readonly storage = appContext.storageService;
+
+ private storeTask?: DelayedTask;
reporting = appContext.reportingService;
@@ -132,25 +127,25 @@
};
}
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('content-change', e => {
this._handleContentChange(e as CustomEvent<{value: string}>);
});
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getEditPrefs().then(prefs => {
this._prefs = prefs;
});
}
/** @override */
- detached() {
- this.cancelDebouncer(DEBOUNCER_STORE);
+ disconnectedCallback() {
+ this.storeTask?.cancel();
+ super.disconnectedCallback();
}
get storageKey() {
@@ -179,7 +174,7 @@
// NOTE: This may be called before attachment (e.g. while parentElement is
// null). Fire title-change in an async so that, if attachment to the DOM
// has been queued, the event can bubble up to the handler in gr-app.
- this.async(() => {
+ setTimeout(() => {
const title = `Editing ${computeTruncatedPath(value.path)}`;
fireTitleChange(this, title);
});
@@ -355,8 +350,8 @@
}
_handleContentChange(e: CustomEvent<{value: string}>) {
- this.debounce(
- DEBOUNCER_STORE,
+ this.storeTask = debounce(
+ this.storeTask,
() => {
const content = e.detail.value;
if (content) {
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
index 8512545..a29d45d 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
@@ -109,7 +109,7 @@
bubbles: true, composed: true,
detail: {value: 'new content value'},
}));
- element.flushDebouncer('store');
+ element.storeTask.flush();
flush();
assert.equal(element._newContent, 'new content value');
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index ec3bd0f..e96f6e4 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -37,8 +37,6 @@
import './settings/gr-cla-view/gr-cla-view';
import './settings/gr-registration-dialog/gr-registration-dialog';
import './settings/gr-settings-view/gr-settings-view';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-app-element_html';
import {getBaseUrl} from '../utils/url-util';
@@ -75,11 +73,13 @@
ShortcutTriggeredEvent,
TitleChangeEventDetail,
DialogChangeEventDetail,
+ EventType,
} from '../types/events';
import {ViewState} from '../types/types';
-import {EventType} from '../utils/event-util';
import {GerritView} from '../services/router/router-model';
import {windowLocationReload} from '../utils/dom-util';
+import {LifeCycle} from '../constants/reporting';
+import {fireIronAnnounce} from '../utils/event-util';
interface ErrorInfo {
text: string;
@@ -98,9 +98,7 @@
// TODO(TS): implement AppElement interface from gr-app-types.ts
@customElement('gr-app-element')
-export class GrAppElement extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrAppElement extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -219,9 +217,12 @@
};
}
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
+ // We just want to instantiate this service somewhere. It is reacting to
+ // model changes and updates the config model, but at the moment the service
+ // is not called from anywhere.
+ appContext.configService;
this._bindKeyboardShortcuts();
document.addEventListener(EventType.PAGE_ERROR, e => {
this._handlePageError(e);
@@ -254,8 +255,11 @@
this.restApiService.getAccount().then(account => {
this._account = account;
- const role = account ? 'user' : 'guest';
- this.reporting.reportLifeCycle(`Started as ${role}`);
+ if (account) {
+ this.reporting.reportLifeCycle(LifeCycle.STARTED_AS_USER);
+ } else {
+ this.reporting.reportLifeCycle(LifeCycle.STARTED_AS_GUEST);
+ }
});
this.restApiService.getConfig().then(config => {
this._serverConfig = config;
@@ -482,7 +486,7 @@
// because _showPluginScreen value does not change. To force restamp,
// change _showPluginScreen value between true and false.
if (isPluginScreen) {
- this.async(() => this.set('_showPluginScreen', true), 1);
+ setTimeout(() => this.set('_showPluginScreen', true), 1);
}
this.set(
'_showDocumentationSearch',
@@ -508,7 +512,7 @@
}
// To fix bug announce read after each new view, we reset announce with
// empty space
- this.fire('iron-announce', {text: ' '}, {bubbles: true});
+ fireIronAnnounce(this, ' ');
}
_handleShortcutTriggered(event: ShortcutTriggeredEvent) {
@@ -544,17 +548,19 @@
this.$.errorView.classList.add('show');
const response = e.detail.response;
const err: ErrorInfo = {
- text: [response.status, response.statusText].join(' '),
+ text: [response?.status, response?.statusText].join(' '),
};
- if (response.status === 404) {
+ if (response?.status === 404) {
err.emoji = '¯\\_(ツ)_/¯';
this._lastError = err;
} else {
err.emoji = 'o_O';
- response.text().then(text => {
- err.moreInfo = text;
- this._lastError = err;
- });
+ if (response) {
+ response.text().then(text => {
+ err.moreInfo = text;
+ this._lastError = err;
+ });
+ }
}
}
diff --git a/polygerrit-ui/app/elements/gr-app-global-var-init.ts b/polygerrit-ui/app/elements/gr-app-global-var-init.ts
index 8a632bb..85a6d49 100644
--- a/polygerrit-ui/app/elements/gr-app-global-var-init.ts
+++ b/polygerrit-ui/app/elements/gr-app-global-var-init.ts
@@ -23,57 +23,16 @@
*/
import {GrAnnotation} from './diff/gr-diff-highlight/gr-annotation';
-import {GrDiffLine, GrDiffLineType} from './diff/gr-diff/gr-diff-line';
-import {GrDiffGroup, GrDiffGroupType} from './diff/gr-diff/gr-diff-group';
-import {getPluginEndpoints} from './shared/gr-js-api-interface/gr-plugin-endpoints';
-import {util} from '../scripts/util';
import {page} from '../utils/page-wrapper-utils';
import {appContext} from '../services/app-context';
-import {
- getPluginLoader,
- PluginLoader,
-} from './shared/gr-js-api-interface/gr-plugin-loader';
import {GrPluginActionContext} from './shared/gr-js-api-interface/gr-plugin-action-context';
-import {
- getPluginNameFromUrl,
- PLUGIN_LOADING_TIMEOUT_MS,
- PRELOADED_PROTOCOL,
- send,
-} from './shared/gr-js-api-interface/gr-api-utils';
-import {getBaseUrl} from '../utils/url-util';
import {GerritNav} from './core/gr-navigation/gr-navigation';
-import {getRootElement} from '../scripts/rootElement';
-import {RevisionInfo} from './shared/revision-info/revision-info';
export function initGlobalVariables() {
window.GrAnnotation = GrAnnotation;
- window.GrDiffLine = GrDiffLine;
- window.GrDiffLineType = GrDiffLineType;
- window.GrDiffGroup = GrDiffGroup;
- window.GrDiffGroupType = GrDiffGroupType;
- window.util = util;
window.page = page;
- window.Auth = appContext.authService;
- window.EventEmitter = appContext.eventEmitter;
- window.PluginLoader = PluginLoader;
window.GrPluginActionContext = GrPluginActionContext;
-
- window._apiUtils = {
- getPluginNameFromUrl,
- send,
- getBaseUrl,
- PRELOADED_PROTOCOL,
- PLUGIN_LOADING_TIMEOUT_MS,
- };
-
window.Gerrit = window.Gerrit || {};
window.Gerrit.Nav = GerritNav;
- window.Gerrit.getRootElement = getRootElement;
window.Gerrit.Auth = appContext.authService;
-
- window.Gerrit._pluginLoader = getPluginLoader();
- // TODO: should define as a getter
- window.Gerrit._endpoints = getPluginEndpoints();
-
- window.Gerrit.RevisionInfo = RevisionInfo;
}
diff --git a/polygerrit-ui/app/elements/gr-app-types.ts b/polygerrit-ui/app/elements/gr-app-types.ts
index 4809562..2ae85f7 100644
--- a/polygerrit-ui/app/elements/gr-app-types.ts
+++ b/polygerrit-ui/app/elements/gr-app-types.ts
@@ -20,11 +20,12 @@
RepoDetailView,
} from './core/gr-navigation/gr-navigation';
import {
+ BasePatchSetNum,
DashboardId,
GroupId,
NumericChangeId,
- PatchSetNum,
RepoName,
+ RevisionPatchSetNum,
UrlEncodedCommentId,
} from '../types/common';
import {GerritView} from '../services/router/router-model';
@@ -99,8 +100,8 @@
project?: RepoName;
commentId?: UrlEncodedCommentId;
path?: string;
- patchNum?: PatchSetNum;
- basePatchNum?: PatchSetNum;
+ patchNum?: RevisionPatchSetNum;
+ basePatchNum?: BasePatchSetNum;
lineNum: number;
leftSide?: boolean;
commentLink?: boolean;
@@ -110,8 +111,8 @@
changeNum: NumericChangeId;
project: RepoName;
edit?: boolean;
- patchNum?: PatchSetNum;
- basePatchNum?: PatchSetNum;
+ patchNum?: RevisionPatchSetNum;
+ basePatchNum?: BasePatchSetNum;
queryMap?: Map<string, string> | URLSearchParams;
}
diff --git a/polygerrit-ui/app/elements/gr-app.ts b/polygerrit-ui/app/elements/gr-app.ts
index f19931f..2d3289d 100644
--- a/polygerrit-ui/app/elements/gr-app.ts
+++ b/polygerrit-ui/app/elements/gr-app.ts
@@ -36,8 +36,6 @@
import {initGlobalVariables} from './gr-app-global-var-init';
import './gr-app-element';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-app_html';
import {initGerritPluginApi} from './shared/gr-js-api-interface/gr-gerrit';
@@ -47,7 +45,7 @@
installPolymerResin(safeTypesBridge);
@customElement('gr-app')
-class GrApp extends GestureEventListeners(LegacyElementMixin(PolymerElement)) {
+class GrApp extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/gr-app_test.js b/polygerrit-ui/app/elements/gr-app_test.js
index 1a04411..8178c89 100644
--- a/polygerrit-ui/app/elements/gr-app_test.js
+++ b/polygerrit-ui/app/elements/gr-app_test.js
@@ -30,12 +30,8 @@
setup(done => {
sinon.stub(appContext.reportingService, 'appStarted');
- stub('gr-account-dropdown', {
- _getTopContent: sinon.stub(),
- });
- stub('gr-router', {
- start: sinon.stub(),
- });
+ stub('gr-account-dropdown', '_getTopContent');
+ stub('gr-router', 'start');
stubRestApi('getAccount').returns(Promise.resolve({}));
stubRestApi('getAccountCapabilities').returns(Promise.resolve({}));
configStub = stubRestApi('getConfig').returns(Promise.resolve({
diff --git a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
deleted file mode 100644
index bbb58fc..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
+++ /dev/null
@@ -1,49 +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 {PluginApi} from '../../../api/plugin';
-import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
-import {HookApi} from '../../../api/hook';
-import {appContext} from '../../../services/app-context';
-
-export class GrChangeMetadataApi implements ChangeMetadataPluginApi {
- private hook: HookApi | null;
-
- public plugin: PluginApi;
-
- private readonly reporting = appContext.reportingService;
-
- constructor(plugin: PluginApi) {
- this.plugin = plugin;
- this.hook = null;
- this.reporting.trackApi(this.plugin, 'metadata', 'constructor');
- }
-
- _createHook() {
- this.hook = this.plugin.hook('change-metadata-item');
- }
-
- onLabelsChanged(callback: (value: unknown) => void) {
- this.reporting.trackApi(this.plugin, 'metadata', 'onLabelsChanged');
- if (!this.hook) {
- this._createHook();
- }
- this.hook!.onAttached((element: Element) =>
- this.plugin.attributeHelper(element).bind('labels', callback)
- );
- return this;
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
index 3ab3efb..e1ec158 100644
--- a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
@@ -15,9 +15,9 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
+import '../../../test/common-test-setup-karma';
+import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
+import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit';
import {PluginApi} from '../../../api/plugin';
import {ChecksPluginApi} from '../../../api/checks';
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
index 423cff9..0e8cbcb 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-endpoint-decorator_html';
import {
@@ -30,9 +28,7 @@
const INIT_PROPERTIES_TIMEOUT_MS = 10000;
@customElement('gr-endpoint-decorator')
-export class GrEndpointDecorator extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEndpointDecorator extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -54,12 +50,12 @@
_endpointCallBack: (info: ModuleInfo) => void = () => {};
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
for (const [el, domHook] of this._domHooks) {
domHook.handleInstanceDetached(el);
}
getPluginEndpoints().onDetachedEndpoint(this.name, this._endpointCallBack);
+ super.disconnectedCallback();
}
_initDecoration(
@@ -71,7 +67,9 @@
return this._initProperties(
el,
plugin,
- this.getContentChildren().find(el => el.nodeName !== 'GR-ENDPOINT-PARAM')
+ // The direct children are slotted into <slot>, so this is identical to
+ // this.shadowRoot.querySelector('slot').assignedElements()[0].
+ this.firstElementChild
).then(el => {
const slotEl = slot
? this.querySelector(`gr-endpoint-slot[name=${slot}]`)
@@ -85,9 +83,16 @@
});
}
+ // As of March 2021 the only known plugin that replaces an endpoint instead
+ // of decorating it is codemirror_editor.
_initReplacement(name: string, plugin: PluginApi): Promise<HTMLElement> {
- this.getContentChildNodes()
+ // The direct children are slotted into <slot>, so they are identical to
+ // this.shadowRoot.querySelector('slot').assignedElements().
+ const directChildren = [...this.childNodes];
+ const shadowChildren = [...(this.shadowRoot?.childNodes ?? [])];
+ [...directChildren, ...shadowChildren]
.filter(node => node.nodeName !== 'GR-ENDPOINT-PARAM')
+ .filter(node => node.nodeName !== 'SLOT')
.forEach(node => (node as ChildNode).remove());
const el = document.createElement(name);
return this._initProperties(el, plugin).then((el: HTMLElement) =>
@@ -102,13 +107,16 @@
_initProperties(
htmlEl: HTMLElement,
plugin: PluginApi,
- content?: HTMLElement
+ content?: Element | null
) {
const el = htmlEl as HTMLElement & {
plugin?: PluginApi;
- content?: HTMLElement;
+ content?: Element;
};
el.plugin = plugin;
+ // The content is (only?) used in ChangeReplyPluginApi.
+ // Maybe it would be better for the consumer side to figure out the content
+ // with something like el.getRootNode().host, etc.
if (content) {
el.content = content;
}
@@ -184,7 +192,6 @@
if (this.name) {
getPluginLoader()
.awaitPluginsLoaded()
- .then(() => getPluginEndpoints().getAndImportPlugins(this.name))
.then(() =>
getPluginEndpoints()
.getDetails(this.name)
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
index c48258d..8138ff0 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import '../../../test/common-test-setup-karma.js';
import './gr-endpoint-decorator.js';
import '../gr-endpoint-param/gr-endpoint-param.js';
@@ -22,7 +21,6 @@
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
import {resetPlugins} from '../../../test/test-utils.js';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
const pluginApi = _testOnly_initGerritPluginApi();
@@ -56,10 +54,8 @@
setup(done => {
resetPlugins();
container = basicFixture.instantiate();
- sinon.stub(getPluginEndpoints(), 'importUrl')
- .callsFake( url => Promise.resolve());
pluginApi.install(p => plugin = p, '0.1',
- 'http://some/plugin/url.html');
+ 'http://some/plugin/url.js');
// Decoration
decorationHook = plugin.registerCustomComponent('first', 'some-module');
decorationHookWithSlot = plugin.registerCustomComponent(
@@ -83,9 +79,6 @@
const endpoints =
Array.from(container.querySelectorAll('gr-endpoint-decorator'));
assert.equal(endpoints.length, 3);
- assert.isTrue(getPluginEndpoints().importUrl.calledWith(
- new URL('http://some/plugin/url.html')
- ));
});
test('decoration', () => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
index 9e9f348..ee89c86 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
@@ -26,9 +24,7 @@
}
@customElement('gr-endpoint-param')
-export class GrEndpointParam extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEndpointParam extends PolymerElement {
@property({type: String, reflectToAttribute: true})
name = '';
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
index 0c2f412..0c6dd4d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
@@ -21,11 +21,6 @@
import {PluginApi} from '../../../api/plugin';
import {appContext} from '../../../services/app-context';
-export interface ListenOptions {
- event?: string;
- capture?: boolean;
-}
-
export class GrEventHelper implements EventHelperPluginApi {
private readonly reporting = appContext.reportingService;
@@ -34,15 +29,6 @@
}
/**
- * Add a callback to arbitrary event.
- * The callback may return false to prevent event bubbling.
- */
- on(event: string, callback: (event: Event) => boolean) {
- this.reporting.trackApi(this.plugin, 'event', 'on');
- return this._listen(this.element, callback, {event});
- }
-
- /**
* Alias for @see onClick
*/
onTap(callback: (event: Event) => boolean) {
@@ -59,33 +45,10 @@
return this._listen(this.element, callback);
}
- /**
- * Alias for @see captureClick
- */
- captureTap(callback: (event: Event) => boolean) {
- this.reporting.trackApi(this.plugin, 'event', 'captureTap');
- return this.captureClick(callback);
- }
-
- /**
- * Add a callback to element click or touch ahead of normal flow.
- * Callback is installed on parent during capture phase.
- * https://www.w3.org/TR/DOM-Level-3-Events/#event-flow
- * The callback may return false to cancel regular event listeners.
- */
- captureClick(callback: (event: Event) => boolean) {
- this.reporting.trackApi(this.plugin, 'event', 'captureClick');
- const parent = this.element.parentElement!;
- return this._listen(parent, callback, {capture: true});
- }
-
_listen(
container: HTMLElement,
- callback: (event: Event) => boolean,
- options?: ListenOptions | null
+ callback: (event: Event) => boolean
): UnsubscribeCallback {
- const capture = options?.capture;
- const event = options?.event || 'click';
const handler = (e: Event) => {
const path = e.composedPath();
if (!path) return;
@@ -103,9 +66,8 @@
}
}
};
- container.addEventListener(event, handler, capture);
- const unsubscribe = () =>
- container.removeEventListener(event, handler, capture);
+ container.addEventListener('click', handler);
+ const unsubscribe = () => container.removeEventListener('click', handler);
return unsubscribe;
}
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
index 547b575..6291e64 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
@@ -71,47 +71,5 @@
flush();
assert.isFalse(tapStub.called);
});
-
- test('captureTap()', done => {
- instance.captureTap(() => {
- done();
- });
- MockInteractions.tap(element);
- });
-
- test('captureClick()', done => {
- instance.captureClick(() => {
- done();
- });
- MockInteractions.tap(element);
- });
-
- test('captureTap() cancels tap()', () => {
- const tapStub = sinon.stub();
- addListener(element.parentElement, 'tap', tapStub);
- instance.captureTap(() => false);
- MockInteractions.tap(element);
- flush();
- assert.isFalse(tapStub.called);
- });
-
- test('captureClick() cancels click()', () => {
- const tapStub = sinon.stub();
- element.addEventListener('click', tapStub);
- instance.captureTap(() => false);
- MockInteractions.tap(element);
- flush();
- assert.isFalse(tapStub.called);
- });
-
- test('on()', done => {
- instance.on('foo', () => {
- done();
- });
- element.dispatchEvent(
- new CustomEvent('foo', {
- composed: true, bubbles: true,
- }));
- });
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
index dc3ebcf..007e4c2 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import {updateStyles} from '@polymer/polymer/lib/mixins/element-mixin';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-external-style_html';
import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
@@ -24,9 +22,7 @@
import {customElement, property} from '@polymer/decorators';
@customElement('gr-external-style')
-class GrExternalStyle extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrExternalStyle extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -56,19 +52,15 @@
}
_importAndApply() {
- getPluginEndpoints()
- .getAndImportPlugins(this.name)
- .then(() => {
- const moduleNames = getPluginEndpoints().getModules(this.name);
- for (const name of moduleNames) {
- this._applyStyle(name);
- }
- });
+ const moduleNames = getPluginEndpoints().getModules(this.name);
+ for (const name of moduleNames) {
+ this._applyStyle(name);
+ }
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._importAndApply();
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.js
index ad30f48..a192f80 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.js
@@ -14,12 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import '../../../test/common-test-setup-karma.js';
import {resetPlugins} from '../../../test/test-utils.js';
import './gr-external-style.js';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
@@ -30,7 +28,7 @@
);
suite('gr-external-style integration tests', () => {
- const TEST_URL = 'http://some.com/plugins/url.html';
+ const TEST_URL = 'http://some.com/plugins/url.js';
let element;
let plugin;
@@ -66,8 +64,6 @@
};
setup(() => {
- sinon.stub(getPluginEndpoints(), 'importUrl')
- .callsFake( url => Promise.resolve());
sinon.stub(getPluginLoader(), 'awaitPluginsLoaded')
.returns(Promise.resolve());
});
@@ -78,27 +74,12 @@
.forEach(style => style.remove());
});
- test('imports plugin-provided module', async () => {
- lateRegister();
- await new Promise(flush);
- assert.isTrue(getPluginEndpoints().importUrl.calledWith(new URL(TEST_URL)));
- });
-
test('applies plugin-provided styles', async () => {
lateRegister();
await new Promise(flush);
assert.isTrue(element._applyStyle.calledWith('some-module'));
});
- test('does not double import', async () => {
- earlyRegister();
- await new Promise(flush);
- plugin.registerStyleModule('foo', 'some-module');
- await new Promise(flush);
- // since loaded, should not call again
- assert.isFalse(getPluginEndpoints().importUrl.calledOnce);
- });
-
test('does not double apply', async () => {
earlyRegister();
await new Promise(flush);
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
index 81b3a16..ac493a2 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
@@ -14,27 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {customElement, property} from '@polymer/decorators';
import {ServerInfo} from '../../../types/common';
@customElement('gr-plugin-host')
-class GrPluginHost extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrPluginHost extends PolymerElement {
@property({type: Object, observer: '_configChanged'})
config?: ServerInfo;
_configChanged(config: ServerInfo) {
const plugins = config.plugin;
- const htmlPlugins = (plugins && plugins.html_resource_paths) || [];
- const jsPlugins = this._handleMigrations(
- (plugins && plugins.js_resource_paths) || [],
- htmlPlugins
- );
+ const jsPlugins = (plugins && plugins.js_resource_paths) || [];
const shouldLoadTheme =
!!config.default_theme &&
!getPluginLoader().isPluginPreloaded('preloaded:gerrit-theme');
@@ -42,30 +34,9 @@
const themeToLoad: string[] = shouldLoadTheme
? [config.default_theme!]
: [];
-
- // Theme should be loaded first if has one to have better UX
- const pluginsPending = themeToLoad.concat(jsPlugins, htmlPlugins);
-
- const pluginOpts: {[key: string]: {sync: boolean}} = {};
-
- if (shouldLoadTheme) {
- // config.default_theme is defined when shouldLoadTheme is true
- // Theme needs to be loaded synchronous.
- pluginOpts[config.default_theme!] = {sync: true};
- }
-
- getPluginLoader().loadPlugins(pluginsPending, pluginOpts);
- }
-
- /**
- * Omit .js plugins that have .html counterparts.
- * For example, if plugin provides foo.js and foo.html, skip foo.js.
- */
- _handleMigrations(jsPlugins: string[], htmlPlugins: string[]) {
- return jsPlugins.filter(url => {
- const counterpart = url.replace(/\.js$/, '.html');
- return !htmlPlugins.includes(counterpart);
- });
+ // Theme should be loaded first for better UX.
+ const pluginsPending = themeToLoad.concat(jsPlugins);
+ getPluginLoader().loadPlugins(pluginsPending);
}
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.js b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.js
index 7a99dc4..3d35aa4 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.js
@@ -34,29 +34,27 @@
sinon.stub(getPluginLoader(), 'loadPlugins');
element.config = {
plugin: {
- html_resource_paths: ['plugins/foo/bar', 'plugins/baz'],
- js_resource_paths: ['plugins/42'],
+ js_resource_paths: ['plugins/42', 'plugins/foo/bar', 'plugins/baz'],
},
};
assert.isTrue(getPluginLoader().loadPlugins.calledOnce);
assert.isTrue(getPluginLoader().loadPlugins.calledWith([
'plugins/42', 'plugins/foo/bar', 'plugins/baz',
- ], {}));
+ ]));
});
test('theme plugins should be loaded if enabled', () => {
sinon.stub(getPluginLoader(), 'loadPlugins');
element.config = {
- default_theme: 'gerrit-theme.html',
+ default_theme: 'gerrit-theme.js',
plugin: {
- html_resource_paths: ['plugins/foo/bar', 'plugins/baz'],
- js_resource_paths: ['plugins/42'],
+ js_resource_paths: ['plugins/42', 'plugins/foo/bar', 'plugins/baz'],
},
};
assert.isTrue(getPluginLoader().loadPlugins.calledOnce);
assert.isTrue(getPluginLoader().loadPlugins.calledWith([
- 'gerrit-theme.html', 'plugins/42', 'plugins/foo/bar', 'plugins/baz',
- ], {'gerrit-theme.html': {sync: true}}));
+ 'gerrit-theme.js', 'plugins/42', 'plugins/foo/bar', 'plugins/baz',
+ ]));
});
test('skip theme if preloaded', () => {
@@ -69,7 +67,7 @@
plugin: {},
};
assert.isTrue(getPluginLoader().loadPlugins.calledOnce);
- assert.isTrue(getPluginLoader().loadPlugins.calledWith([], {}));
+ assert.isTrue(getPluginLoader().loadPlugins.calledWith([]));
});
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
index 7c6587a..af6a159 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-plugin-popup_html';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
@@ -34,9 +32,7 @@
};
}
@customElement('gr-plugin-popup')
-export class GrPluginPopup extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrPluginPopup extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.js
index f2d83e8..6ce77b1 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.js
@@ -25,10 +25,8 @@
setup(() => {
element = basicFixture.instantiate();
- stub('gr-overlay', {
- open: sinon.stub().returns(Promise.resolve()),
- close: sinon.stub(),
- });
+ stub('gr-overlay', 'open').callsFake(() => Promise.resolve());
+ stub('gr-overlay', 'close');
});
test('exists', () => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.ts b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.ts
deleted file mode 100644
index a9aba13..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-plugin-repo-command_html';
-import {customElement, property} from '@polymer/decorators';
-import {fireEvent} from '../../../utils/event-util';
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-plugin-repo-command': GrPluginRepoCommand;
- }
-}
-@customElement('gr-plugin-repo-command')
-export class GrPluginRepoCommand extends PolymerElement {
- @property({type: String})
- title = '';
-
- static get template() {
- return htmlTemplate;
- }
-
- _handleClick() {
- fireEvent(this, 'command-tap');
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command_html.ts b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command_html.ts
deleted file mode 100644
index 6eee643..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command_html.ts
+++ /dev/null
@@ -1,28 +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';
-
-export const htmlTemplate = html`
- <style include="shared-styles">
- :host {
- display: block;
- margin-bottom: var(--spacing-xxl);
- }
- </style>
- <h3>[[title]]</h3>
- <gr-button on-click="_handleClick">[[title]]</gr-button>
-`;
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
deleted file mode 100644
index 51e9112..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import './gr-plugin-repo-command';
-import {ConfigInfo} from '../../../types/common';
-import {PluginApi} from '../../../api/plugin';
-import {RepoCommandCallback, RepoPluginApi} from '../../../api/repo';
-import {HookApi} from '../../../api/hook';
-import {appContext} from '../../../services/app-context';
-
-/**
- * Parameters provided on repo-command endpoint
- */
-export interface GrRepoCommandEndpointEl extends HTMLElement {
- repoName: string;
- config: ConfigInfo;
-}
-
-export class GrRepoApi implements RepoPluginApi {
- private hook?: HookApi;
-
- private readonly reporting = appContext.reportingService;
-
- constructor(readonly plugin: PluginApi) {
- this.reporting.trackApi(this.plugin, 'repo', 'constructor');
- }
-
- // TODO(TS): should mark as public since used in gr-change-metadata-api
- _createHook(title: string) {
- return this.plugin.hook('repo-command').onAttached(element => {
- const pluginCommand = document.createElement('gr-plugin-repo-command');
- pluginCommand.title = title;
- element.appendChild(pluginCommand);
- });
- }
-
- createCommand(title: string, callback: RepoCommandCallback) {
- this.reporting.trackApi(this.plugin, 'repo', 'createCommand');
- if (this.hook) {
- console.warn('Already set up.');
- return this;
- }
- this.hook = this._createHook(title);
- this.hook.onAttached(element => {
- if (callback(element.repoName, element.config) === false) {
- element.hidden = true;
- }
- });
- return this;
- }
-
- onTap(callback: (event: Event) => boolean) {
- this.reporting.trackApi(this.plugin, 'repo', 'onTap');
- if (!this.hook) {
- console.warn('Call createCommand first.');
- return this;
- }
- this.hook.onAttached(element => {
- this.plugin.eventHelper(element).on('command-tap', callback);
- });
- return this;
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.js b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.js
deleted file mode 100644
index 9e24fda..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import '../gr-endpoint-decorator/gr-endpoint-decorator.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
-<gr-endpoint-decorator name="repo-command">
- </gr-endpoint-decorator>
-`);
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-repo-api tests', () => {
- let repoApi;
-
- setup(() => {
- let plugin;
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
- getPluginLoader().loadPlugins([]);
- repoApi = plugin.project();
- });
-
- teardown(() => {
- repoApi = null;
- });
-
- test('exists', () => {
- assert.isOk(repoApi);
- });
-
- test('works', done => {
- const attachedStub = sinon.stub();
- const tapStub = sinon.stub();
- repoApi
- .createCommand('foo', attachedStub)
- .onTap(tapStub);
- const element = basicFixture.instantiate();
- flush(() => {
- assert.isTrue(attachedStub.called);
- const pluginCommand = element.shadowRoot
- .querySelector('gr-plugin-repo-command');
- assert.isOk(pluginCommand);
- const btn = pluginCommand.shadowRoot
- .querySelector('gr-button');
- assert.isOk(btn);
- assert.equal(btn.textContent, 'foo');
- assert.isFalse(tapStub.called);
- MockInteractions.tap(btn);
- assert.isTrue(tapStub.called);
- done();
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
deleted file mode 100644
index 3f75c0a..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Settings
- *
- * 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 '../../settings/gr-settings-view/gr-settings-item';
-import '../../settings/gr-settings-view/gr-settings-menu-item';
-import {PluginApi} from '../../../api/plugin';
-import {SettingsPluginApi} from '../../../api/settings';
-import {appContext} from '../../../services/app-context';
-
-export class GrSettingsApi implements SettingsPluginApi {
- private _token: string;
-
- private _title = '(no title)';
-
- private _moduleName?: string;
-
- private readonly reporting = appContext.reportingService;
-
- constructor(readonly plugin: PluginApi) {
- this.reporting.trackApi(this.plugin, 'settings', 'constructor');
- // Generate default screen URL token, specific to plugin, and unique(ish).
- this._token = plugin.getPluginName() + Math.random().toString(36).substr(5);
- }
-
- title(newTitle: string) {
- this.reporting.trackApi(this.plugin, 'settings', 'title');
- this._title = newTitle;
- return this;
- }
-
- token(newToken: string) {
- this.reporting.trackApi(this.plugin, 'settings', 'token');
- this._token = newToken;
- return this;
- }
-
- module(newModuleName: string) {
- this.reporting.trackApi(this.plugin, 'settings', 'module');
- this._moduleName = newModuleName;
- return this;
- }
-
- build() {
- this.reporting.trackApi(this.plugin, 'settings', 'build');
- if (!this._moduleName) {
- throw new Error('Settings screen custom element not defined!');
- }
- const token = `x/${this.plugin.getPluginName()}/${this._token}`;
- this.plugin.hook('settings-menu-item').onAttached(el => {
- const menuItem = document.createElement('gr-settings-menu-item');
- menuItem.title = this._title;
- menuItem.setAttribute('href', `#${token}`);
- el.appendChild(menuItem);
- });
- const moduleName = this._moduleName;
- return this.plugin.hook('settings-screen').onAttached(el => {
- const item = document.createElement('gr-settings-item');
- item.title = this._title;
- item.anchor = token;
- item.appendChild(document.createElement(moduleName));
- el.appendChild(item);
- });
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.js b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.js
deleted file mode 100644
index 893f3e4..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import '../gr-endpoint-decorator/gr-endpoint-decorator.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
-<gr-endpoint-decorator name="settings-menu-item">
- </gr-endpoint-decorator>
- <gr-endpoint-decorator name="settings-screen">
- </gr-endpoint-decorator>
-`);
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-settings-api tests', () => {
- let settingsApi;
-
- setup(() => {
- let plugin;
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
- getPluginLoader().loadPlugins([]);
- settingsApi = plugin.settings();
- });
-
- teardown(() => {
- settingsApi = null;
- });
-
- test('exists', () => {
- assert.isOk(settingsApi);
- });
-
- test('works', done => {
- settingsApi
- .title('foo')
- .token('bar')
- .module('some-settings-screen')
- .build();
- const element = basicFixture.instantiate();
- flush(() => {
- const [menuItemEl, itemEl] = element;
- const menuItem = menuItemEl.shadowRoot
- .querySelector('gr-settings-menu-item');
- assert.isOk(menuItem);
- assert.equal(menuItem.title, 'foo');
- assert.equal(menuItem.href, '#x/testplugin/bar');
- const item = itemEl.shadowRoot
- .querySelector('gr-settings-item');
- assert.isOk(item);
- assert.equal(item.title, 'foo');
- assert.equal(item.anchor, 'x/testplugin/bar');
- done();
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
deleted file mode 100644
index 9a15bf5..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @license
- * Copyright (C) 2019 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 {StyleObject, StylesPluginApi} from '../../../api/styles';
-import {appContext} from '../../../services/app-context';
-import {PluginApi} from '../../../api/plugin';
-
-/**
- * @fileoverview We should consider dropping support for this API:
- *
- * 1. we need to try avoid using `innerHTML` for xss concerns
- * 2. we have css variables which are more recommended way to custom styling
- */
-
-let styleObjectCount = 0;
-
-interface PgElement extends Element {
- __pg_js_api_style_tags: {
- [className: string]: boolean;
- };
-}
-
-export class GrStyleObject implements StyleObject {
- private className = '';
-
- constructor(private readonly rulesStr: string) {
- this.className = `__pg_js_api_class_${styleObjectCount}`;
- styleObjectCount++;
- }
-
- /**
- * Creates a new unique CSS class and injects it in a root node of the element
- * if it hasn't been added yet. A root node is an document or is the
- * associated shadowRoot. This class can be added to any element with the same
- * root node.
- */
- getClassName(element: Element) {
- let rootNodeEl = element.getRootNode();
- if (rootNodeEl === document) {
- rootNodeEl = document.head;
- }
- // TODO(TS): type casting to have correct interface
- // maybe move this __pg_xxx to attribute
- const rootNode: PgElement = rootNodeEl as PgElement;
- if (!rootNode.__pg_js_api_style_tags) {
- rootNode.__pg_js_api_style_tags = {};
- }
- if (!rootNode.__pg_js_api_style_tags[this.className]) {
- const styleTag = document.createElement('style');
- styleTag.innerHTML = `.${this.className} { ${this.rulesStr} }`;
- rootNode.appendChild(styleTag);
- rootNode.__pg_js_api_style_tags[this.className] = true;
- }
- return this.className;
- }
-
- /**
- * Apply shared style to the element.
- */
- apply(element: Element) {
- element.classList.add(this.getClassName(element));
- }
-}
-
-/**
- * TODO(TS): move to util
- */
-export class GrStylesApi implements StylesPluginApi {
- private readonly reporting = appContext.reportingService;
-
- constructor(readonly plugin: PluginApi) {
- this.reporting.trackApi(this.plugin, 'styles', 'constructor');
- }
-
- /**
- * Creates a new GrStyleObject with specified style properties.
- */
- css(ruleStr: string) {
- this.reporting.trackApi(this.plugin, 'styles', 'css');
- return new GrStyleObject(ruleStr);
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.js b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.js
deleted file mode 100644
index 1c606cd..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api_test.js
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * @license
- * Copyright (C) 2019 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 '../../shared/gr-js-api-interface/gr-js-api-interface.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-class GrStyleTestElement extends PolymerElement {
- static get is() { return 'gr-style-test-element'; }
-
- static get template() {
- return html`<div id="wrapper"></div>`;
- }
-}
-
-customElements.define(GrStyleTestElement.is, GrStyleTestElement);
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-styles-api tests', () => {
- let stylesApi;
-
- setup(() => {
- let plugin;
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
- getPluginLoader().loadPlugins([]);
- stylesApi = plugin.styles();
- });
-
- teardown(() => {
- stylesApi = null;
- });
-
- test('exists', () => {
- assert.isOk(stylesApi);
- });
-
- test('css', () => {
- const styleObject = stylesApi.css('background: red');
- assert.isDefined(styleObject);
- });
-
- suite('GrStyleObject tests', () => {
- let stylesApi;
- let displayInlineStyle;
- let displayNoneStyle;
- let elementsToRemove;
-
- setup(() => {
- let plugin;
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
- getPluginLoader().loadPlugins([]);
- stylesApi = plugin.styles();
- displayInlineStyle = stylesApi.css('display: inline');
- displayNoneStyle = stylesApi.css('display: none');
- elementsToRemove = [];
- });
-
- teardown(() => {
- displayInlineStyle = null;
- displayNoneStyle = null;
- stylesApi = null;
- elementsToRemove.forEach(element => {
- element.remove();
- });
- elementsToRemove = null;
- sinon.restore();
- });
-
- function createNestedElements(parentElement) {
- /* parentElement
- * |--- element1
- * |--- element2
- * |--- element3
- **/
- const element1 = document.createElement('div');
- const element2 = document.createElement('div');
- const element3 = document.createElement('div');
- parentElement.appendChild(element1);
- parentElement.appendChild(element2);
- element2.appendChild(element3);
-
- if (parentElement === document.body) {
- elementsToRemove.push(element1);
- elementsToRemove.push(element2);
- }
-
- return [element1, element2, element3];
- }
-
- test('getClassName - body level elements', () => {
- const bodyLevelElements = createNestedElements(document.body);
-
- testGetClassName(bodyLevelElements);
- });
-
- test('getClassName - elements inside polymer element', () => {
- const polymerElement = document.createElement('gr-style-test-element');
- document.body.appendChild(polymerElement);
- elementsToRemove.push(polymerElement);
- const contentElements = createNestedElements(polymerElement.$.wrapper);
-
- testGetClassName(contentElements);
- });
-
- function testGetClassName(elements) {
- assertAllElementsHaveDefaultStyle(elements);
-
- const className1 = displayInlineStyle.getClassName(elements[0]);
- const className2 = displayNoneStyle.getClassName(elements[1]);
- const className3 = displayInlineStyle.getClassName(elements[2]);
-
- assert.notEqual(className2, className1);
- assert.equal(className3, className1);
-
- assertAllElementsHaveDefaultStyle(elements);
-
- elements[0].classList.add(className1);
- elements[1].classList.add(className2);
- elements[2].classList.add(className1);
-
- assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
- }
-
- test('apply - body level elements', () => {
- const bodyLevelElements = createNestedElements(document.body);
-
- testApply(bodyLevelElements);
- });
-
- test('apply - elements inside polymer element', () => {
- const polymerElement = document.createElement('gr-style-test-element');
- document.body.appendChild(polymerElement);
- elementsToRemove.push(polymerElement);
- const contentElements = createNestedElements(polymerElement.$.wrapper);
-
- testApply(contentElements);
- });
-
- function testApply(elements) {
- assertAllElementsHaveDefaultStyle(elements);
- displayInlineStyle.apply(elements[0]);
- displayNoneStyle.apply(elements[1]);
- displayInlineStyle.apply(elements[2]);
- assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
- }
-
- function assertAllElementsHaveDefaultStyle(elements) {
- for (const element of elements) {
- assert.equal(getComputedStyle(element).getPropertyValue('display'),
- 'block');
- }
- }
-
- function assertDisplayPropertyValues(elements, expectedDisplayValues) {
- for (let i = 0; i < elements.length; i++) {
- assert.equal(
- getComputedStyle(elements[i]).getPropertyValue('display'),
- expectedDisplayValues[i]);
- }
- }
- });
-});
-
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
deleted file mode 100644
index c7be7f6..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import './gr-custom-plugin-header';
-import {GrCustomPluginHeader} from './gr-custom-plugin-header';
-import {PluginApi} from '../../../api/plugin';
-import {ThemePluginApi} from '../../../api/theme';
-import {appContext} from '../../../services/app-context';
-
-/**
- * Defines api for theme, can be used to set header logo and title.
- */
-export class GrThemeApi implements ThemePluginApi {
- private readonly reporting = appContext.reportingService;
-
- constructor(private readonly plugin: PluginApi) {
- this.reporting.trackApi(this.plugin, 'theme', 'constructor');
- }
-
- setHeaderLogoAndTitle(logoUrl: string, title: string) {
- this.reporting.trackApi(this.plugin, 'theme', 'setHeaderLogoAndTitle');
- this.plugin.hook('header-title', {replace: true}).onAttached(element => {
- const customHeader: GrCustomPluginHeader = document.createElement(
- 'gr-custom-plugin-header'
- );
- customHeader.logoUrl = logoUrl;
- customHeader.title = title;
- element.appendChild(customHeader);
- });
- }
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.js b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.js
deleted file mode 100644
index 787ab0b..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import '../gr-endpoint-decorator/gr-endpoint-decorator.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const headerTitleFixture = fixtureFromTemplate(html`
-<gr-endpoint-decorator name="header-title">
- <span class="titleText"></span>
- </gr-endpoint-decorator>
-`);
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-theme-api tests', () => {
- let theme;
-
- setup(() => {
- let plugin;
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
- theme = plugin.theme();
- });
-
- teardown(() => {
- theme = null;
- });
-
- test('exists', () => {
- assert.isOk(theme);
- });
-
- suite('header-title', () => {
- let customHeader;
-
- setup(() => {
- headerTitleFixture.instantiate();
- stub('gr-custom-plugin-header', {
- /** @override */
- ready() { customHeader = this; },
- });
- getPluginLoader().loadPlugins([]);
- });
-
- test('sets logo and title', done => {
- theme.setHeaderLogoAndTitle('foo.jpg', 'bar');
- flush(() => {
- assert.isNotNull(customHeader);
- assert.equal(customHeader.logoUrl, 'foo.jpg');
- assert.equal(customHeader.title, 'bar');
- done();
- });
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
index 5786576..7ef5a73 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-info_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -30,9 +28,7 @@
import {fireEvent} from '../../../utils/event-util';
@customElement('gr-account-info')
-export class GrAccountInfo extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountInfo extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
index fe4ef8e..6ca484d 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
@@ -41,9 +41,7 @@
<section class$="[[_hideAvatarChangeUrl(_avatarChangeUrl)]]">
<span class="title"></span>
<span class="value">
- <a href$="[[_avatarChangeUrl]]">
- Change avatar
- </a>
+ <a href$="[[_avatarChangeUrl]]"> Change avatar </a>
</span>
</section>
<section>
@@ -67,13 +65,16 @@
<span class="title">Username</span>
<span hidden$="[[usernameMutable]]" class="value">[[_username]]</span>
<span hidden$="[[!usernameMutable]]" class="value">
- <iron-input on-keydown="_handleKeydown" bind-value="{{_username}}">
+ <iron-input
+ on-keydown="_handleKeydown"
+ bind-value="{{_username}}"
+ id="usernameIronInput"
+ >
<input
is="iron-input"
id="usernameInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
- bind-value="{{_username}}"
/>
</iron-input>
</span>
@@ -82,13 +83,16 @@
<label class="title" for="nameInput">Full name</label>
<span hidden$="[[nameMutable]]" class="value">[[_account.name]]</span>
<span hidden$="[[!nameMutable]]" class="value">
- <iron-input on-keydown="_handleKeydown" bind-value="{{_account.name}}">
+ <iron-input
+ on-keydown="_handleKeydown"
+ bind-value="{{_account.name}}"
+ id="nameIronInput"
+ >
<input
is="iron-input"
id="nameInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
- bind-value="{{_account.name}}"
/>
</iron-input>
</span>
@@ -105,7 +109,6 @@
id="displayNameInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
- bind-value="{{_account.display_name}}"
/>
</iron-input>
</span>
@@ -122,7 +125,6 @@
id="statusInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
- bind-value="{{_account.status}}"
/>
</iron-input>
</span>
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
similarity index 67%
rename from polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js
rename to polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
index c7cb44e..6aa7f7c 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
@@ -15,52 +15,63 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-account-info.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import '../../../test/common-test-setup-karma';
+import './gr-account-info';
+import {SinonSpyMember, stubRestApi} from '../../../test/test-utils';
+import {GrAccountInfo} from './gr-account-info';
+import {AccountDetailInfo, ServerInfo} from '../../../types/common';
+import {
+ createAccountWithIdNameAndEmail,
+ createPreferences,
+ createServerInfo,
+} from '../../../test/test-data-generators';
+import {IronInputElement} from '@polymer/iron-input';
+import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
const basicFixture = fixtureFromElement('gr-account-info');
suite('gr-account-info tests', () => {
- let element;
- let account;
- let config;
+ let element!: GrAccountInfo;
+ let account: AccountDetailInfo;
+ let config: ServerInfo;
- function valueOf(title) {
- const sections = element.root.querySelectorAll('section');
+ function queryIronInput(selector: string): IronInputElement {
+ const input = element.root?.querySelector<IronInputElement>(selector);
+ if (!input) assert.fail(`<iron-input> with id ${selector} not found.`);
+ return input;
+ }
+
+ function valueOf(title: string): Element {
+ const sections = element.root?.querySelectorAll('section') ?? [];
let titleEl;
for (let i = 0; i < sections.length; i++) {
titleEl = sections[i].querySelector('.title');
- if (titleEl.textContent === title) {
- return sections[i].querySelector('.value');
+ if (titleEl?.textContent === title) {
+ const el = sections[i].querySelector('.value');
+ if (el) return el;
}
}
+ assert.fail(`element with title ${title} not found`);
}
- setup(done => {
- account = {
- _account_id: 123,
- name: 'user name',
- email: 'user@email',
- username: 'user username',
- registered: '2000-01-01 00:00:00.000000000',
- };
- config = {auth: {editable_account_fields: []}};
+ setup(async () => {
+ account = createAccountWithIdNameAndEmail(123) as AccountDetailInfo;
+ config = createServerInfo();
stubRestApi('getAccount').returns(Promise.resolve(account));
stubRestApi('getConfig').returns(Promise.resolve(config));
- stubRestApi('getPreferences').returns(
- Promise.resolve({time_format: 'HHMM_12'}));
+ stubRestApi('getPreferences').returns(Promise.resolve(createPreferences()));
element = basicFixture.instantiate();
- // Allow the element to render.
- element.loadData().then(() => { flush(done); });
+ await element.loadData();
+ await flush();
});
test('basic account info render', () => {
assert.isFalse(element._loading);
- assert.equal(valueOf('ID').textContent, account._account_id);
+ assert.equal(valueOf('ID').textContent, `${account._account_id}`);
assert.equal(valueOf('Email').textContent, account.email);
assert.equal(valueOf('Username').textContent, account.username);
});
@@ -77,8 +88,9 @@
});
test('full name render (mutable)', () => {
- element.set('_serverConfig',
- {auth: {editable_account_fields: ['FULL_NAME']}});
+ element.set('_serverConfig', {
+ auth: {editable_account_fields: ['FULL_NAME']},
+ });
const section = element.$.nameSection;
const displaySpan = section.querySelectorAll('.value')[0];
@@ -86,7 +98,7 @@
assert.isTrue(element.nameMutable);
assert.isTrue(displaySpan.hasAttribute('hidden'));
- assert.equal(element.$.nameInput.bindValue, account.name);
+ assert.equal(queryIronInput('#nameIronInput').bindValue, account.name);
assert.isFalse(inputSpan.hasAttribute('hidden'));
});
@@ -102,8 +114,9 @@
});
test('username render (mutable)', () => {
- element.set('_serverConfig',
- {auth: {editable_account_fields: ['USER_NAME']}});
+ element.set('_serverConfig', {
+ auth: {editable_account_fields: ['USER_NAME']},
+ });
element.set('_account.username', '');
element.set('_username', '');
@@ -113,32 +126,34 @@
assert.isTrue(element.usernameMutable);
assert.isTrue(displaySpan.hasAttribute('hidden'));
- assert.equal(element.$.usernameInput.bindValue, account.username);
+ assert.equal(
+ queryIronInput('#usernameIronInput').bindValue,
+ account.username
+ );
assert.isFalse(inputSpan.hasAttribute('hidden'));
});
suite('account info edit', () => {
- let nameChangedSpy;
- let usernameChangedSpy;
- let statusChangedSpy;
- let nameStub;
- let usernameStub;
- let statusStub;
+ let nameChangedSpy: SinonSpyMember<typeof element._nameChanged>;
+ let usernameChangedSpy: SinonSpyMember<typeof element._usernameChanged>;
+ let statusChangedSpy: SinonSpyMember<typeof element._statusChanged>;
+ let nameStub: SinonStubbedMember<RestApiService['setAccountName']>;
+ let usernameStub: SinonStubbedMember<RestApiService['setAccountUsername']>;
+ let statusStub: SinonStubbedMember<RestApiService['setAccountStatus']>;
setup(() => {
nameChangedSpy = sinon.spy(element, '_nameChanged');
usernameChangedSpy = sinon.spy(element, '_usernameChanged');
statusChangedSpy = sinon.spy(element, '_statusChanged');
- element.set('_serverConfig',
- {auth: {editable_account_fields: ['FULL_NAME', 'USER_NAME']}});
+ element.set('_serverConfig', {
+ auth: {editable_account_fields: ['FULL_NAME', 'USER_NAME']},
+ });
- nameStub = stubRestApi('setAccountName').callsFake(
- name => Promise.resolve());
- usernameStub = stubRestApi('setAccountUsername')
- .callsFake(username => Promise.resolve());
- statusStub = stubRestApi(
- 'setAccountStatus').callsFake(
- status => Promise.resolve());
+ nameStub = stubRestApi('setAccountName').returns(Promise.resolve());
+ usernameStub = stubRestApi('setAccountUsername').returns(
+ Promise.resolve()
+ );
+ statusStub = stubRestApi('setAccountStatus').returns(Promise.resolve());
});
test('name', done => {
@@ -206,24 +221,21 @@
});
suite('edit name and status', () => {
- let nameChangedSpy;
- let statusChangedSpy;
- let nameStub;
- let statusStub;
+ let nameChangedSpy: SinonSpyMember<typeof element._nameChanged>;
+ let statusChangedSpy: SinonSpyMember<typeof element._statusChanged>;
+ let nameStub: SinonStubbedMember<RestApiService['setAccountName']>;
+ let statusStub: SinonStubbedMember<RestApiService['setAccountStatus']>;
setup(() => {
nameChangedSpy = sinon.spy(element, '_nameChanged');
statusChangedSpy = sinon.spy(element, '_statusChanged');
- element.set('_serverConfig',
- {auth: {editable_account_fields: ['FULL_NAME']}});
+ element.set('_serverConfig', {
+ auth: {editable_account_fields: ['FULL_NAME']},
+ });
- nameStub = stubRestApi('setAccountName').callsFake(
- name => Promise.resolve());
- statusStub = stubRestApi(
- 'setAccountStatus').callsFake(
- status => Promise.resolve());
- stubRestApi('setAccountUsername').callsFake(
- username => Promise.resolve());
+ nameStub = stubRestApi('setAccountName').returns(Promise.resolve());
+ statusStub = stubRestApi('setAccountStatus').returns(Promise.resolve());
+ stubRestApi('setAccountUsername').returns(Promise.resolve());
});
test('set name and status', done => {
@@ -254,17 +266,14 @@
});
suite('set status but read name', () => {
- let statusChangedSpy;
- let statusStub;
+ let statusChangedSpy: SinonSpyMember<typeof element._statusChanged>;
+ let statusStub: SinonStubbedMember<RestApiService['setAccountStatus']>;
setup(() => {
statusChangedSpy = sinon.spy(element, '_statusChanged');
- element.set('_serverConfig',
- {auth: {editable_account_fields: []}});
+ element.set('_serverConfig', {auth: {editable_account_fields: []}});
- statusStub = stubRestApi(
- 'setAccountStatus').callsFake(
- status => Promise.resolve());
+ statusStub = stubRestApi('setAccountStatus').returns(Promise.resolve());
});
test('read full name but set status', done => {
@@ -320,4 +329,3 @@
assert.equal(element._hideAvatarChangeUrl('https://example.com'), '');
});
});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
index da180c3..c1cff72 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
@@ -17,8 +17,6 @@
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-agreements-list_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -27,9 +25,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-agreements-list')
-export class GrAgreementsList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAgreementsList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -40,8 +36,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.loadData();
}
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.js b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
similarity index 61%
rename from polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.js
rename to polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
index c8ce574..f08976f 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
@@ -14,41 +14,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-agreements-list.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import '../../../test/common-test-setup-karma';
+import './gr-agreements-list';
+import {stubRestApi} from '../../../test/test-utils';
+import {GrAgreementsList} from './gr-agreements-list';
+import {ContributorAgreementInfo} from '../../../types/common';
const basicFixture = fixtureFromElement('gr-agreements-list');
suite('gr-agreements-list tests', () => {
- let element;
- let agreements;
+ let element: GrAgreementsList;
setup(done => {
- agreements = [{
- url: 'some url',
- description: 'Agreements 1 description',
- name: 'Agreements 1',
- }];
+ const agreements: ContributorAgreementInfo[] = [
+ {
+ url: 'some url',
+ description: 'Agreements 1 description',
+ name: 'Agreements 1',
+ },
+ ];
stubRestApi('getAccountAgreements').returns(Promise.resolve(agreements));
element = basicFixture.instantiate();
- element.loadData().then(() => { flush(done); });
+ element.loadData().then(() => {
+ flush(done);
+ });
});
test('renders', () => {
- const rows = element.root.querySelectorAll('tbody tr');
-
+ const rows = element.root?.querySelectorAll('tbody tr') ?? [];
assert.equal(rows.length, 1);
const nameCells = Array.from(rows).map(row =>
- row.querySelectorAll('td')[0].textContent.trim()
+ row.querySelectorAll('td')[0].textContent?.trim()
);
assert.equal(nameCells[0], 'Agreements 1');
});
});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
index df927d6..d13b2a9 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
@@ -19,8 +19,6 @@
import '../../../styles/shared-styles';
import '../../../styles/gr-form-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-table-editor_html';
import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
@@ -29,15 +27,13 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-change-table-editor')
-class GrChangeTableEditor extends ChangeTableMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrChangeTableEditor extends ChangeTableMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@property({type: Array, notify: true})
- displayedColumns?: string[];
+ displayedColumns: string[] = [];
@property({type: Boolean, notify: true})
showNumber?: boolean;
@@ -46,7 +42,7 @@
serverConfig?: ServerInfo;
@property({type: Array})
- defaultColumns?: string[];
+ defaultColumns: string[] = [];
flagsService = appContext.flagsService;
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.js b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.js
deleted file mode 100644
index db5c035..0000000
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-change-table-editor.js';
-
-const basicFixture = fixtureFromElement('gr-change-table-editor');
-
-suite('gr-change-table-editor tests', () => {
- let element;
- let columns;
-
- setup(() => {
- element = basicFixture.instantiate();
-
- columns = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Reviewers',
- 'Comments',
- 'Repo',
- 'Branch',
- 'Updated',
- ];
-
- element.set('displayedColumns', columns);
- element.showNumber = false;
- element.serverConfig = {
- change: {},
- };
- flush();
- });
-
- test('renders', () => {
- const rows = element.shadowRoot
- .querySelector('tbody').querySelectorAll('tr');
- let tds;
-
- // The `+ 1` is for the number column, which isn't included in the change
- // table behavior's list.
- assert.equal(rows.length, element.defaultColumns.length + 1);
- for (let i = 0; i < element.defaultColumns.length; i++) {
- tds = rows[i + 1].querySelectorAll('td');
- assert.equal(tds[0].textContent, element.defaultColumns[i]);
- }
- });
-
- test('disabled experiments are hidden', () => {
- assert.isFalse(element.displayedColumns.includes('Assignee'));
- element.set('displayedColumns', columns);
- element.serverConfig = {
- change: {
- enable_assignee: true,
- },
- };
- flush();
- assert.isTrue(element.displayedColumns.includes('Assignee'));
- });
-
- test('hide item', () => {
- const checkbox = element.shadowRoot
- .querySelector('table tr:nth-child(2) input');
- const isChecked = checkbox.checked;
- const displayedLength = element.displayedColumns.length;
- assert.isTrue(isChecked);
-
- MockInteractions.tap(checkbox);
- flush();
-
- assert.equal(element.displayedColumns.length, displayedLength - 1);
- });
-
- test('show item', () => {
- element.set('displayedColumns', [
- 'Status',
- 'Owner',
- 'Assignee',
- 'Repo',
- 'Branch',
- 'Updated',
- ]);
- // trigger computation of enabled displayed columns
- element.serverConfig = {
- change: {},
- };
- flush();
- const checkbox = element.shadowRoot
- .querySelector('table tr:nth-child(2) input');
- const isChecked = checkbox.checked;
- const displayedLength = element.displayedColumns.length;
- assert.isFalse(isChecked);
- assert.equal(element.shadowRoot
- .querySelector('table').style.display, '');
-
- MockInteractions.tap(checkbox);
- flush();
-
- assert.equal(element.displayedColumns.length,
- displayedLength + 1);
- });
-
- test('_getDisplayedColumns', () => {
- const enabledColumns = columns.filter(column => element.isColumnEnabled(
- column, element.serverConfig, []
- ));
- assert.deepEqual(element._getDisplayedColumns(), enabledColumns);
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('.checkboxContainer input[name=Subject]'));
- assert.deepEqual(element._getDisplayedColumns(),
- enabledColumns.filter(c => c !== 'Subject'));
- });
-
- test('_handleCheckboxContainerClick relays taps to checkboxes', () => {
- sinon.stub(element, '_handleNumberCheckboxClick');
- sinon.stub(element, '_handleTargetClick');
-
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('table tr:first-of-type .checkboxContainer'));
- assert.isTrue(element._handleNumberCheckboxClick.calledOnce);
- assert.isFalse(element._handleTargetClick.called);
-
- MockInteractions.tap(
- element.shadowRoot
- .querySelector('table tr:last-of-type .checkboxContainer'));
- assert.isTrue(element._handleNumberCheckboxClick.calledOnce);
- assert.isTrue(element._handleTargetClick.calledOnce);
- });
-
- test('_handleNumberCheckboxClick', () => {
- sinon.spy(element, '_handleNumberCheckboxClick');
-
- MockInteractions
- .tap(element.shadowRoot
- .querySelector('.checkboxContainer input[name=number]'));
- assert.isTrue(element._handleNumberCheckboxClick.calledOnce);
- assert.isTrue(element.showNumber);
-
- MockInteractions
- .tap(element.shadowRoot
- .querySelector('.checkboxContainer input[name=number]'));
- assert.isTrue(element._handleNumberCheckboxClick.calledTwice);
- assert.isFalse(element.showNumber);
- });
-
- test('_handleTargetClick', () => {
- sinon.spy(element, '_handleTargetClick');
- assert.include(element.displayedColumns, 'Subject');
- MockInteractions
- .tap(element.shadowRoot
- .querySelector('.checkboxContainer input[name=Subject]'));
- assert.isTrue(element._handleTargetClick.calledOnce);
- assert.notInclude(element.displayedColumns, 'Subject');
- });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts
new file mode 100644
index 0000000..4f61972
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts
@@ -0,0 +1,182 @@
+/**
+ * @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.
+ */
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import '../../../test/common-test-setup-karma';
+import './gr-change-table-editor';
+import {GrChangeTableEditor} from './gr-change-table-editor';
+import {queryAndAssert} from '../../../test/test-utils';
+import {createServerInfo} from '../../../test/test-data-generators';
+import {ServerInfo} from '../../../types/common';
+
+const basicFixture = fixtureFromElement('gr-change-table-editor');
+
+suite('gr-change-table-editor tests', () => {
+ let element: GrChangeTableEditor;
+ let columns: string[];
+
+ setup(async () => {
+ element = basicFixture.instantiate();
+
+ columns = [
+ 'Subject',
+ 'Status',
+ 'Owner',
+ 'Assignee',
+ 'Reviewers',
+ 'Comments',
+ 'Repo',
+ 'Branch',
+ 'Updated',
+ ];
+
+ element.set('displayedColumns', columns);
+ element.showNumber = false;
+ element.serverConfig = createServerInfo();
+ await flush();
+ });
+
+ test('renders', () => {
+ const rows = queryAndAssert(element, 'tbody').querySelectorAll('tr');
+ let tds;
+
+ // The `+ 1` is for the number column, which isn't included in the change
+ // table behavior's list.
+ assert.equal(rows.length, element.defaultColumns.length + 1);
+ for (let i = 0; i < element.defaultColumns.length; i++) {
+ tds = rows[i + 1].querySelectorAll('td');
+ assert.equal(tds[0].textContent, element.defaultColumns[i]);
+ }
+ });
+
+ test('disabled experiments are hidden', () => {
+ assert.isFalse(element.displayedColumns.includes('Assignee'));
+ element.set('displayedColumns', columns);
+ const config: ServerInfo = {...createServerInfo()};
+ config.change.enable_assignee = true;
+ element.serverConfig = config;
+ flush();
+ assert.isTrue(element.displayedColumns.includes('Assignee'));
+ });
+
+ test('hide item', () => {
+ const checkbox = queryAndAssert<HTMLInputElement>(
+ element,
+ 'table tr:nth-child(2) input'
+ );
+ const isChecked = checkbox.checked;
+ const displayedLength = element.displayedColumns.length;
+ assert.isTrue(isChecked);
+
+ MockInteractions.tap(checkbox);
+ flush();
+
+ assert.equal(element.displayedColumns.length, displayedLength - 1);
+ });
+
+ test('show item', () => {
+ element.set('displayedColumns', [
+ 'Status',
+ 'Owner',
+ 'Assignee',
+ 'Repo',
+ 'Branch',
+ 'Updated',
+ ]);
+ // trigger computation of enabled displayed columns
+ element.serverConfig = createServerInfo();
+ flush();
+ const checkbox = queryAndAssert<HTMLInputElement>(
+ element,
+ 'table tr:nth-child(2) input'
+ );
+ const isChecked = checkbox.checked;
+ const displayedLength = element.displayedColumns.length;
+ assert.isFalse(isChecked);
+ const table = queryAndAssert<HTMLTableElement>(element, 'table');
+ assert.equal(table.style.display, '');
+
+ MockInteractions.tap(checkbox);
+ flush();
+
+ assert.equal(element.displayedColumns.length, displayedLength + 1);
+ });
+
+ test('_getDisplayedColumns', () => {
+ const enabledColumns = columns.filter(column =>
+ element.isColumnEnabled(column, element.serverConfig!, [])
+ );
+ assert.deepEqual(element._getDisplayedColumns(), enabledColumns);
+ const input = queryAndAssert<HTMLInputElement>(
+ element,
+ '.checkboxContainer input[name=Subject]'
+ );
+ MockInteractions.tap(input);
+ assert.deepEqual(
+ element._getDisplayedColumns(),
+ enabledColumns.filter(c => c !== 'Subject')
+ );
+ });
+
+ test('_handleCheckboxContainerClick relays taps to checkboxes', () => {
+ const checkBoxClickStub = sinon.stub(element, '_handleNumberCheckboxClick');
+ const targetClickStub = sinon.stub(element, '_handleTargetClick');
+
+ const firstContainer = queryAndAssert(
+ element,
+ 'table tr:first-of-type .checkboxContainer'
+ );
+ MockInteractions.tap(firstContainer);
+ assert.isTrue(checkBoxClickStub.calledOnce);
+ assert.isFalse(targetClickStub.called);
+
+ const lastContainer = queryAndAssert(
+ element,
+ 'table tr:last-of-type .checkboxContainer'
+ );
+ MockInteractions.tap(lastContainer);
+ assert.isTrue(checkBoxClickStub.calledOnce);
+ assert.isTrue(targetClickStub.calledOnce);
+ });
+
+ test('_handleNumberCheckboxClick', () => {
+ const checkBoxClickSpy = sinon.spy(element, '_handleNumberCheckboxClick');
+
+ const numberInput = queryAndAssert(
+ element,
+ '.checkboxContainer input[name=number]'
+ );
+ MockInteractions.tap(numberInput);
+ assert.isTrue(checkBoxClickSpy.calledOnce);
+ assert.isTrue(element.showNumber);
+
+ MockInteractions.tap(numberInput);
+ assert.isTrue(checkBoxClickSpy.calledTwice);
+ assert.isFalse(element.showNumber);
+ });
+
+ test('_handleTargetClick', () => {
+ const targetClickSpy = sinon.spy(element, '_handleTargetClick');
+ assert.include(element.displayedColumns, 'Subject');
+ const subjectInput = queryAndAssert(
+ element,
+ '.checkboxContainer input[name=Subject]'
+ );
+ MockInteractions.tap(subjectInput);
+ assert.isTrue(targetClickSpy.calledOnce);
+ assert.notInclude(element.displayedColumns, 'Subject');
+ });
+});
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
index 9f7fadf..b0b7ab8 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
@@ -19,8 +19,6 @@
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-cla-view_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -40,9 +38,7 @@
}
@customElement('gr-cla-view')
-export class GrClaView extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrClaView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -71,8 +67,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.loadData();
fireTitleChange(this, 'New Contributor Agreement');
@@ -155,7 +151,7 @@
_disableAgreements(
item: ContributorAgreementInfo,
- groups: GroupInfo[],
+ groups?: GroupInfo[],
signedAgreements?: ContributorAgreementInfo[]
) {
if (!groups) return false;
@@ -189,7 +185,7 @@
// then hides the text box and submit button.
_computeHideAgreementClass(
name: string,
- contributorAgreements: ContributorAgreementInfo[]
+ contributorAgreements?: ContributorAgreementInfo[]
) {
if (!contributorAgreements) return '';
return contributorAgreements.some(
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
index 59203d3..887382e 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
@@ -84,9 +84,7 @@
>
Agreement already submitted.
</div>
- <div class="agreementsUrl">
- [[item.description]]
- </div>
+ <div class="agreementsUrl">[[item.description]]</div>
</template>
<div
id="claNewAgreement"
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.js b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.js
deleted file mode 100644
index 7c11136..0000000
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.js
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-cla-view.js';
-import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-cla-view');
-
-suite('gr-cla-view tests', () => {
- let element;
- const signedAgreements = [{
- name: 'CLA',
- description: 'Contributor License Agreement',
- url: 'static/cla.html',
- }];
- const auth = {
- name: 'Individual',
- description: 'test-description',
- url: 'static/cla_individual.html',
- auto_verify_group: {
- url: '#/admin/groups/uuid-e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
- options: {
- visible_to_all: true,
- },
- group_id: 20,
- owner: 'CLA Accepted - Individual',
- owner_id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
- created_on: '2017-07-31 15:11:04.000000000',
- id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
- name: 'CLA Accepted - Individual',
- },
- };
-
- const auth2 = {
- name: 'Individual2',
- description: 'test-description2',
- url: 'static/cla_individual2.html',
- auto_verify_group: {
- url: '#/admin/groups/uuid-bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
- options: {},
- group_id: 21,
- owner: 'CLA Accepted - Individual2',
- owner_id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
- created_on: '2017-07-31 15:25:42.000000000',
- id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
- name: 'CLA Accepted - Individual2',
- },
- };
-
- const auth3 = {
- name: 'CLA',
- description: 'Contributor License Agreement',
- url: 'static/cla_individual.html',
- };
-
- const config = {
- auth: {
- use_contributor_agreements: true,
- contributor_agreements: [
- {
- name: 'Individual',
- description: 'test-description',
- url: 'static/cla_individual.html',
- },
- {
- name: 'CLA',
- description: 'Contributor License Agreement',
- url: 'static/cla.html',
- }],
- },
- };
- const config2 = {
- auth: {
- use_contributor_agreements: true,
- contributor_agreements: [
- {
- name: 'Individual2',
- description: 'test-description2',
- url: 'static/cla_individual2.html',
- },
- ],
- },
- };
- const groups = [{
- options: {visible_to_all: true},
- id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
- group_id: 3,
- name: 'CLA Accepted - Individual',
- },
- ];
-
- setup(done => {
- stubRestApi('getConfig').returns(Promise.resolve(config));
- stubRestApi('getAccountGroups').returns(Promise.resolve(groups));
- stubRestApi('getAccountAgreements').returns(
- Promise.resolve(signedAgreements));
- element = basicFixture.instantiate();
- element.loadData().then(() => { flush(done); });
- });
-
- test('renders as expected with signed agreement', () => {
- const agreementSections = dom(element.root)
- .querySelectorAll('.contributorAgreementButton');
- const agreementSubmittedTexts = dom(element.root)
- .querySelectorAll('.alreadySubmittedText');
- assert.equal(agreementSections.length, 2);
- assert.isFalse(agreementSections[0].querySelector('input').disabled);
- assert.equal(getComputedStyle(agreementSubmittedTexts[0]).display,
- 'none');
- assert.isTrue(agreementSections[1].querySelector('input').disabled);
- assert.notEqual(getComputedStyle(agreementSubmittedTexts[1]).display,
- 'none');
- });
-
- test('_disableAgreements', () => {
- // In the auto verify group and have not yet signed agreement
- assert.isTrue(
- element._disableAgreements(auth, groups, signedAgreements));
- // Not in the auto verify group and have not yet signed agreement
- assert.isFalse(
- element._disableAgreements(auth2, groups, signedAgreements));
- // Not in the auto verify group, have signed agreement
- assert.isTrue(
- element._disableAgreements(auth3, groups, signedAgreements));
- // Make sure the undefined check works
- assert.isFalse(
- element._disableAgreements(auth, undefined, signedAgreements));
- });
-
- test('_hideAgreements', () => {
- // Not in the auto verify group and have not yet signed agreement
- assert.equal(
- element._hideAgreements(auth, groups, signedAgreements), '');
- // In the auto verify group
- assert.equal(
- element._hideAgreements(auth2, groups, signedAgreements), 'hide');
- // Not in the auto verify group, have signed agreement
- assert.equal(
- element._hideAgreements(auth3, groups, signedAgreements), '');
- });
-
- test('_disableAgreementsText', () => {
- assert.isFalse(element._disableAgreementsText('I AGREE'));
- assert.isTrue(element._disableAgreementsText('I DO NOT AGREE'));
- });
-
- test('_computeHideAgreementClass', () => {
- assert.equal(
- element._computeHideAgreementClass(
- auth.name, config.auth.contributor_agreements),
- 'hideAgreementsTextBox');
- assert.isNotOk(
- element._computeHideAgreementClass(
- auth.name, config2.auth.contributor_agreements));
- });
-
- test('_getAgreementsUrl', () => {
- assert.equal(element._getAgreementsUrl(
- 'http://test.org/test.html'), 'http://test.org/test.html');
- assert.equal(element._getAgreementsUrl(
- 'test_cla.html'), '/test_cla.html');
- });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts
new file mode 100644
index 0000000..9f54cd1
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts
@@ -0,0 +1,210 @@
+/**
+ * @license
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '../../../test/common-test-setup-karma';
+import './gr-cla-view';
+import {queryAll, queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {GrClaView} from './gr-cla-view';
+import {
+ ContributorAgreementInfo,
+ GroupId,
+ GroupInfo,
+ GroupName,
+ ServerInfo,
+} from '../../../types/common';
+import {AuthType} from '../../../constants/constants';
+import {createServerInfo} from '../../../test/test-data-generators';
+
+const basicFixture = fixtureFromElement('gr-cla-view');
+
+suite('gr-cla-view tests', () => {
+ let element: GrClaView;
+ const signedAgreements = [
+ {
+ name: 'CLA',
+ description: 'Contributor License Agreement',
+ url: 'static/cla.html',
+ },
+ ];
+ const auth: ContributorAgreementInfo = {
+ name: 'Individual',
+ description: 'test-description',
+ url: 'static/cla_individual.html',
+ auto_verify_group: {
+ url: '#/admin/groups/uuid-e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+ options: {
+ visible_to_all: true,
+ },
+ group_id: '20',
+ owner: 'CLA Accepted - Individual',
+ owner_id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+ created_on: '2017-07-31 15:11:04.000000000',
+ id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0' as GroupId,
+ name: 'CLA Accepted - Individual' as GroupName,
+ },
+ };
+
+ const auth2: ContributorAgreementInfo = {
+ name: 'Individual2',
+ description: 'test-description2',
+ url: 'static/cla_individual2.html',
+ auto_verify_group: {
+ url: '#/admin/groups/uuid-bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
+ options: {
+ visible_to_all: false,
+ },
+ group_id: '21',
+ owner: 'CLA Accepted - Individual2',
+ owner_id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
+ created_on: '2017-07-31 15:25:42.000000000',
+ id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb' as GroupId,
+ name: 'CLA Accepted - Individual2' as GroupName,
+ },
+ };
+
+ const auth3: ContributorAgreementInfo = {
+ name: 'CLA',
+ description: 'Contributor License Agreement',
+ url: 'static/cla_individual.html',
+ };
+
+ const config: ServerInfo = {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [],
+ use_contributor_agreements: true,
+ contributor_agreements: [
+ {
+ name: 'Individual',
+ description: 'test-description',
+ url: 'static/cla_individual.html',
+ },
+ {
+ name: 'CLA',
+ description: 'Contributor License Agreement',
+ url: 'static/cla.html',
+ },
+ ],
+ },
+ };
+ const config2: ServerInfo = {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [],
+ use_contributor_agreements: true,
+ contributor_agreements: [
+ {
+ name: 'Individual2',
+ description: 'test-description2',
+ url: 'static/cla_individual2.html',
+ },
+ ],
+ },
+ };
+ const groups: GroupInfo[] = [
+ {
+ options: {visible_to_all: true},
+ id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0' as GroupId,
+ group_id: '3',
+ name: 'CLA Accepted - Individual' as GroupName,
+ },
+ ];
+
+ setup(done => {
+ stubRestApi('getConfig').returns(Promise.resolve(config));
+ stubRestApi('getAccountGroups').returns(Promise.resolve(groups));
+ stubRestApi('getAccountAgreements').returns(
+ Promise.resolve(signedAgreements)
+ );
+ element = basicFixture.instantiate();
+ element.loadData().then(() => {
+ flush(done);
+ });
+ });
+
+ test('renders as expected with signed agreement', () => {
+ const agreementSections = queryAll(element, '.contributorAgreementButton');
+ const agreementSubmittedTexts = queryAll(element, '.alreadySubmittedText');
+ assert.equal(agreementSections.length, 2);
+ assert.isFalse(
+ queryAndAssert<HTMLInputElement>(agreementSections[0], 'input').disabled
+ );
+ assert.equal(getComputedStyle(agreementSubmittedTexts[0]).display, 'none');
+ assert.isTrue(
+ queryAndAssert<HTMLInputElement>(agreementSections[1], 'input').disabled
+ );
+ assert.notEqual(
+ getComputedStyle(agreementSubmittedTexts[1]).display,
+ 'none'
+ );
+ });
+
+ test('_disableAgreements', () => {
+ // In the auto verify group and have not yet signed agreement
+ assert.isTrue(element._disableAgreements(auth, groups, signedAgreements));
+ // Not in the auto verify group and have not yet signed agreement
+ assert.isFalse(element._disableAgreements(auth2, groups, signedAgreements));
+ // Not in the auto verify group, have signed agreement
+ assert.isTrue(element._disableAgreements(auth3, groups, signedAgreements));
+ // Make sure the undefined check works
+ assert.isFalse(
+ element._disableAgreements(auth, undefined, signedAgreements)
+ );
+ });
+
+ test('_hideAgreements', () => {
+ // Not in the auto verify group and have not yet signed agreement
+ assert.equal(element._hideAgreements(auth, groups, signedAgreements), '');
+ // In the auto verify group
+ assert.equal(
+ element._hideAgreements(auth2, groups, signedAgreements),
+ 'hide'
+ );
+ // Not in the auto verify group, have signed agreement
+ assert.equal(element._hideAgreements(auth3, groups, signedAgreements), '');
+ });
+
+ test('_disableAgreementsText', () => {
+ assert.isFalse(element._disableAgreementsText('I AGREE'));
+ assert.isTrue(element._disableAgreementsText('I DO NOT AGREE'));
+ });
+
+ test('_computeHideAgreementClass', () => {
+ assert.equal(
+ element._computeHideAgreementClass(
+ auth.name,
+ config.auth.contributor_agreements
+ ),
+ 'hideAgreementsTextBox'
+ );
+ assert.isNotOk(
+ element._computeHideAgreementClass(
+ auth.name,
+ config2.auth.contributor_agreements
+ )
+ );
+ });
+
+ test('_getAgreementsUrl', () => {
+ assert.equal(
+ element._getAgreementsUrl('http://test.org/test.html'),
+ 'http://test.org/test.html'
+ );
+ assert.equal(element._getAgreementsUrl('test_cla.html'), '/test_cla.html');
+ });
+});
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
index 411d3aa..5e2c5cb 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
@@ -18,8 +18,6 @@
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-edit-preferences_html';
import {customElement, property} from '@polymer/decorators';
@@ -37,9 +35,7 @@
};
}
@customElement('gr-edit-preferences')
-export class GrEditPreferences extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEditPreferences extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
deleted file mode 100644
index cffd1ae..0000000
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * @license
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-edit-preferences.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-edit-preferences');
-
-suite('gr-edit-preferences tests', () => {
- let element;
-
- let editPreferences;
-
- function valueOf(title, fieldsetid) {
- const sections = element.$[fieldsetid].querySelectorAll('section');
- let titleEl;
- for (let i = 0; i < sections.length; i++) {
- titleEl = sections[i].querySelector('.title');
- if (titleEl.textContent.trim() === title) {
- return sections[i].querySelector('.value');
- }
- }
- }
-
- setup(() => {
- editPreferences = {
- auto_close_brackets: false,
- cursor_blink_rate: 0,
- hide_line_numbers: false,
- hide_top_menu: false,
- indent_unit: 2,
- indent_with_tabs: false,
- key_map_type: 'DEFAULT',
- line_length: 100,
- line_wrapping: false,
- match_brackets: true,
- show_base: false,
- show_tabs: true,
- show_whitespace_errors: true,
- syntax_highlighting: true,
- tab_size: 8,
- theme: 'DEFAULT',
- };
-
- stubRestApi('getEditPreferences').returns(Promise.resolve(editPreferences));
-
- element = basicFixture.instantiate();
-
- return element.loadData();
- });
-
- test('renders', () => {
- // Rendered with the expected preferences selected.
- assert.equal(valueOf('Tab width', 'editPreferences')
- .firstElementChild.bindValue, editPreferences.tab_size);
- assert.equal(valueOf('Columns', 'editPreferences')
- .firstElementChild.bindValue, editPreferences.line_length);
- assert.equal(valueOf('Indent unit', 'editPreferences')
- .firstElementChild.bindValue, editPreferences.indent_unit);
- assert.equal(valueOf('Syntax highlighting', 'editPreferences')
- .firstElementChild.checked, editPreferences.syntax_highlighting);
- assert.equal(valueOf('Show tabs', 'editPreferences')
- .firstElementChild.checked, editPreferences.show_tabs);
- assert.equal(valueOf('Match brackets', 'editPreferences')
- .firstElementChild.checked, editPreferences.match_brackets);
- assert.equal(valueOf('Line wrapping', 'editPreferences')
- .firstElementChild.checked, editPreferences.line_wrapping);
- assert.equal(valueOf('Indent with tabs', 'editPreferences')
- .firstElementChild.checked, editPreferences.indent_with_tabs);
- assert.equal(valueOf('Auto close brackets', 'editPreferences')
- .firstElementChild.checked, editPreferences.auto_close_brackets);
-
- assert.isFalse(element.hasUnsavedChanges);
- });
-
- test('save changes', () => {
- stubRestApi('saveEditPreferences')
- .returns(Promise.resolve());
- const showTabsCheckbox = valueOf('Show tabs', 'editPreferences')
- .firstElementChild;
- showTabsCheckbox.checked = false;
- element._handleEditShowTabsChanged();
-
- assert.isTrue(element.hasUnsavedChanges);
-
- // Save the change.
- return element.save().then(() => {
- assert.isFalse(element.hasUnsavedChanges);
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts
new file mode 100644
index 0000000..bfdcaa0
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.ts
@@ -0,0 +1,125 @@
+/**
+ * @license
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-edit-preferences';
+import {stubRestApi} from '../../../test/test-utils';
+import {GrEditPreferences} from './gr-edit-preferences';
+import {EditPreferencesInfo} from '../../../types/common';
+import {IronInputElement} from '@polymer/iron-input';
+
+const basicFixture = fixtureFromElement('gr-edit-preferences');
+
+suite('gr-edit-preferences tests', () => {
+ let element: GrEditPreferences;
+
+ let editPreferences: EditPreferencesInfo;
+
+ function valueOf(title: string, id: string): Element {
+ const sections = element.root?.querySelectorAll(`#${id} section`) ?? [];
+ let titleEl;
+ for (let i = 0; i < sections.length; i++) {
+ titleEl = sections[i].querySelector('.title');
+ if (titleEl?.textContent?.trim() === title) {
+ const el = sections[i].querySelector('.value');
+ if (el) return el;
+ }
+ }
+ assert.fail(`element with title ${title} not found`);
+ }
+
+ setup(async () => {
+ editPreferences = {
+ auto_close_brackets: false,
+ cursor_blink_rate: 0,
+ hide_line_numbers: false,
+ hide_top_menu: false,
+ indent_unit: 2,
+ indent_with_tabs: false,
+ key_map_type: 'DEFAULT',
+ line_length: 100,
+ line_wrapping: false,
+ match_brackets: true,
+ show_base: false,
+ show_tabs: true,
+ show_whitespace_errors: true,
+ syntax_highlighting: true,
+ tab_size: 8,
+ theme: 'DEFAULT',
+ };
+
+ stubRestApi('getEditPreferences').returns(Promise.resolve(editPreferences));
+
+ element = basicFixture.instantiate();
+
+ await element.loadData();
+ await flush();
+ });
+
+ test('renders', () => {
+ // Rendered with the expected preferences selected.
+ const tabWidthInput = valueOf('Tab width', 'editPreferences')
+ .firstElementChild as IronInputElement;
+ assert.equal(tabWidthInput.bindValue, `${editPreferences.tab_size}`);
+
+ const columnsInput = valueOf('Columns', 'editPreferences')
+ .firstElementChild as IronInputElement;
+ assert.equal(columnsInput.bindValue, `${editPreferences.line_length}`);
+
+ const indentInput = valueOf('Indent unit', 'editPreferences')
+ .firstElementChild as IronInputElement;
+ assert.equal(indentInput.bindValue, `${editPreferences.indent_unit}`);
+
+ const syntaxInput = valueOf('Syntax highlighting', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(syntaxInput.checked, editPreferences.syntax_highlighting);
+
+ const tabsInput = valueOf('Show tabs', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(tabsInput.checked, editPreferences.show_tabs);
+
+ const bracketsInput = valueOf('Match brackets', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(bracketsInput.checked, editPreferences.match_brackets);
+
+ const wrappingInput = valueOf('Line wrapping', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(wrappingInput.checked, editPreferences.line_wrapping);
+
+ const indentTabsInput = valueOf('Indent with tabs', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(indentTabsInput.checked, editPreferences.indent_with_tabs);
+
+ const autoCloseInput = valueOf('Auto close brackets', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ assert.equal(autoCloseInput.checked, editPreferences.auto_close_brackets);
+
+ assert.isFalse(element.hasUnsavedChanges);
+ });
+
+ test('save changes', async () => {
+ const showTabsCheckbox = valueOf('Show tabs', 'editPreferences')
+ .firstElementChild as HTMLInputElement;
+ showTabsCheckbox.checked = false;
+ element._handleEditShowTabsChanged();
+
+ assert.isTrue(element.hasUnsavedChanges);
+
+ await element.save();
+ assert.isFalse(element.hasUnsavedChanges);
+ });
+});
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
index 9960d83..74c6ac0 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
@@ -18,8 +18,6 @@
import '../../shared/gr-button/gr-button';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-email-editor_html';
import {customElement, property} from '@polymer/decorators';
@@ -27,9 +25,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-email-editor')
-export class GrEmailEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEmailEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
index bc4a4d2..e4c1584 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-email-editor.js';
+import '../../../test/common-test-setup-karma';
+import './gr-email-editor';
import {GrEmailEditor} from './gr-email-editor';
import {spyRestApi, stubRestApi} from '../../../test/test-utils';
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
index 0fd0ad9..afbd67e 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
@@ -21,8 +21,6 @@
import '../../shared/gr-overlay/gr-overlay';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-gpg-editor_html';
import {customElement, property} from '@polymer/decorators';
@@ -46,9 +44,7 @@
}
}
@customElement('gr-gpg-editor')
-export class GrGpgEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrGpgEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
index c69bebd..a367969 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../../../styles/gr-form-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-group-list_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -31,9 +29,7 @@
}
}
@customElement('gr-group-list')
-export class GrGroupList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrGroupList extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
index 0ae3490..5f98a82 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
@@ -46,9 +46,7 @@
<template is="dom-repeat" items="[[_groups]]">
<tr>
<td class="nameColumn">
- <a href$="[[_computeGroupPath(item)]]">
- [[item.name]]
- </a>
+ <a href$="[[_computeGroupPath(item)]]"> [[item.name]] </a>
</td>
<td>[[item.description]]</td>
<td class="visibleCell">[[_computeVisibleToAll(item)]]</td>
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
index 9bb4b00..610ea30 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
@@ -19,8 +19,6 @@
import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
import '../../shared/gr-overlay/gr-overlay';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-http-password_html';
import {property, customElement} from '@polymer/decorators';
@@ -40,9 +38,7 @@
}
@customElement('gr-http-password')
-export class GrHttpPassword extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrHttpPassword extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -59,8 +55,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.loadData();
}
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
index 837332a..d65304c 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
@@ -19,8 +19,6 @@
import '../../admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-overlay/gr-overlay';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-identities_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -39,9 +37,7 @@
}
@customElement('gr-identities')
-export class GrIdentities extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrIdentities extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
index 34af7eb..ef5d72f 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
@@ -64,9 +64,7 @@
filter="filterIdentities"
>
<tr>
- <td class="statusColumn">
- [[_computeIsTrusted(item.trusted)]]
- </td>
+ <td class="statusColumn">[[_computeIsTrusted(item.trusted)]]</td>
<td class="emailAddressColumn">[[item.email_address]]</td>
<td class="identityColumn">
[[_computeIdentity(item.identity)]]
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index 805c9ca..0ff5e98 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -20,17 +20,13 @@
import '../../../styles/shared-styles';
import '../../../styles/gr-form-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-menu-editor_html';
import {customElement, property} from '@polymer/decorators';
import {TopMenuItemInfo} from '../../../types/common';
@customElement('gr-menu-editor')
-export class GrMenuEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrMenuEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
index 85e692d..39a5d54 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
@@ -18,8 +18,6 @@
import '../../../styles/gr-form-styles';
import '../../shared/gr-button/gr-button';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-registration-dialog_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -43,9 +41,7 @@
}
@customElement('gr-registration-dialog')
-export class GrRegistrationDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRegistrationDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.js b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.js
deleted file mode 100644
index 1088585..0000000
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * @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.
- */
-import '../../../test/common-test-setup-karma.js';
-import './gr-registration-dialog.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-registration-dialog');
-
-suite('gr-registration-dialog tests', () => {
- let element;
- let account;
-
- let _listeners;
-
- setup(() => {
- _listeners = {};
-
- account = {
- name: 'name',
- username: null,
- email: 'email',
- secondary_emails: [
- 'email2',
- 'email3',
- ],
- };
-
- stubRestApi('getAccount').returns(Promise.resolve(account));
- stubRestApi('setAccountName').callsFake(name => {
- account.name = name;
- return Promise.resolve();
- });
- stubRestApi('setAccountUsername').callsFake(username => {
- account.username = username;
- return Promise.resolve();
- });
- stubRestApi('setPreferredAccountEmail').callsFake(email => {
- account.email = email;
- return Promise.resolve();
- });
- stubRestApi('getConfig').returns(
- Promise.resolve({auth: {editable_account_fields: ['USER_NAME']}}));
-
- element = basicFixture.instantiate();
-
- return element.loadData();
- });
-
- teardown(() => {
- for (const [eventType, listeners] of Object.entries(_listeners)) {
- element.removeEventListener(eventType, listeners);
- }
- });
-
- function listen(eventType) {
- return new Promise(resolve => {
- _listeners[eventType] = function() { resolve(); };
- element.addEventListener(eventType, _listeners[eventType]);
- });
- }
-
- function save(opt_action) {
- const promise = listen('account-detail-update');
- if (opt_action) {
- opt_action();
- } else {
- MockInteractions.tap(element.$.saveButton);
- }
- return promise;
- }
-
- function close(opt_action) {
- const promise = listen('close');
- if (opt_action) {
- opt_action();
- } else {
- MockInteractions.tap(element.$.closeButton);
- }
- return promise;
- }
-
- test('fires the close event on close', done => {
- close().then(done);
- });
-
- test('fires the close event on save', done => {
- close(() => {
- MockInteractions.tap(element.$.saveButton);
- }).then(done);
- });
-
- test('saves account details', done => {
- flush(() => {
- element.$.name.value = 'new name';
- element.$.username.value = 'new username';
- element.$.email.value = 'email3';
-
- // Nothing should be committed yet.
- assert.equal(account.name, 'name');
- assert.isNotOk(account.username);
- assert.equal(account.email, 'email');
-
- // Save and verify new values are committed.
- save()
- .then(() => {
- assert.equal(account.name, 'new name');
- assert.equal(account.username, 'new username');
- assert.equal(account.email, 'email3');
- })
- .then(done);
- });
- });
-
- test('email select properly populated', done => {
- element._account = {email: 'foo', secondary_emails: ['bar', 'baz']};
- flush(() => {
- assert.equal(element.$.email.value, 'foo');
- done();
- });
- });
-
- test('save btn disabled', () => {
- const compute = element._computeSaveDisabled;
- assert.isTrue(compute('', '', false));
- assert.isTrue(compute('', 'test', false));
- assert.isTrue(compute('test', '', false));
- assert.isTrue(compute('test', 'test', true));
- assert.isFalse(compute('test', 'test', false));
- });
-
- test('_computeUsernameMutable', () => {
- assert.isTrue(element._computeUsernameMutable(
- {auth: {editable_account_fields: ['USER_NAME']}}, null));
- assert.isFalse(element._computeUsernameMutable(
- {auth: {editable_account_fields: ['USER_NAME']}}, 'abc'));
- assert.isFalse(element._computeUsernameMutable(
- {auth: {editable_account_fields: []}}, null));
- assert.isFalse(element._computeUsernameMutable(
- {auth: {editable_account_fields: []}}, 'abc'));
- });
-});
-
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
new file mode 100644
index 0000000..ccb7404
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
@@ -0,0 +1,208 @@
+/**
+ * @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.
+ */
+import '../../../test/common-test-setup-karma';
+import {GrRegistrationDialog} from './gr-registration-dialog';
+import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {
+ AccountDetailInfo,
+ EmailAddress,
+ Timestamp,
+} from '../../../types/common';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import {AuthType, EditableAccountField} from '../../../constants/constants';
+import {createServerInfo} from '../../../test/test-data-generators';
+
+const basicFixture = fixtureFromElement('gr-registration-dialog');
+
+suite('gr-registration-dialog tests', () => {
+ let element: GrRegistrationDialog;
+ let account: AccountDetailInfo;
+
+ let _listeners: {[key: string]: EventListenerOrEventListenerObject};
+
+ setup(() => {
+ _listeners = {};
+
+ account = {
+ name: 'name',
+ email: 'email' as EmailAddress,
+ secondary_emails: ['email2', 'email3'],
+ registered_on: '2018-02-08 18:49:18.000000000' as Timestamp,
+ };
+
+ stubRestApi('getAccount').returns(Promise.resolve(account));
+ stubRestApi('setAccountName').callsFake(name => {
+ account.name = name;
+ return Promise.resolve();
+ });
+ stubRestApi('setAccountUsername').callsFake(username => {
+ account.username = username;
+ return Promise.resolve();
+ });
+ stubRestApi('setPreferredAccountEmail').callsFake(email => {
+ account.email = email as EmailAddress;
+ return Promise.resolve();
+ });
+ stubRestApi('getConfig').returns(
+ Promise.resolve({
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [EditableAccountField.USER_NAME],
+ },
+ })
+ );
+
+ element = basicFixture.instantiate();
+
+ return element.loadData();
+ });
+
+ teardown(() => {
+ for (const [eventType, listeners] of Object.entries(_listeners)) {
+ element.removeEventListener(eventType, listeners);
+ }
+ });
+
+ function listen(eventType: string): Promise<void> {
+ return new Promise(resolve => {
+ _listeners[eventType] = function () {
+ resolve();
+ };
+ element.addEventListener(eventType, _listeners[eventType]);
+ });
+ }
+
+ function save() {
+ const promise = listen('account-detail-update');
+ MockInteractions.tap(queryAndAssert(element, '#saveButton'));
+ return promise;
+ }
+
+ function close(opt_action?: Function) {
+ const promise = listen('close');
+ if (opt_action) {
+ opt_action();
+ } else {
+ MockInteractions.tap(queryAndAssert(element, '#closeButton'));
+ }
+ return promise;
+ }
+
+ test('fires the close event on close', done => {
+ close().then(done);
+ });
+
+ test('fires the close event on save', done => {
+ close(() =>
+ MockInteractions.tap(queryAndAssert(element, '#saveButton'))
+ ).then(done);
+ });
+
+ test('saves account details', done => {
+ flush(() => {
+ element.$.name.value = 'new name';
+ element.$.username.value = 'new username';
+ element.$.email.value = 'email3';
+
+ // Nothing should be committed yet.
+ assert.equal(account.name, 'name');
+ assert.isNotOk(account.username);
+ assert.equal(account.email, 'email' as EmailAddress);
+
+ // Save and verify new values are committed.
+ save()
+ .then(() => {
+ assert.equal(account.name, 'new name');
+ assert.equal(account.username, 'new username');
+ assert.equal(account.email, 'email3' as EmailAddress);
+ })
+ .then(done);
+ });
+ });
+
+ test('email select properly populated', done => {
+ element._account = {
+ email: 'foo' as EmailAddress,
+ secondary_emails: ['bar', 'baz'],
+ };
+ flush(() => {
+ assert.equal(element.$.email.value, 'foo');
+ done();
+ });
+ });
+
+ test('save btn disabled', () => {
+ const compute = element._computeSaveDisabled;
+ assert.isTrue(compute('', '', false));
+ assert.isTrue(compute('', 'test', false));
+ assert.isTrue(compute('test', '', false));
+ assert.isTrue(compute('test', 'test', true));
+ assert.isFalse(compute('test', 'test', false));
+ });
+
+ test('_computeUsernameMutable', () => {
+ assert.isTrue(
+ element._computeUsernameMutable(
+ {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [EditableAccountField.USER_NAME],
+ },
+ },
+ undefined
+ )
+ );
+ assert.isFalse(
+ element._computeUsernameMutable(
+ {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [EditableAccountField.USER_NAME],
+ },
+ },
+ 'abc'
+ )
+ );
+ assert.isFalse(
+ element._computeUsernameMutable(
+ {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [],
+ },
+ },
+ undefined
+ )
+ );
+ assert.isFalse(
+ element._computeUsernameMutable(
+ {
+ ...createServerInfo(),
+ auth: {
+ auth_type: AuthType.HTTP,
+ editable_account_fields: [],
+ },
+ },
+ 'abc'
+ )
+ );
+ });
+});
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
index 5d80a84d..7540960 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-settings-item_html';
import {property, customElement} from '@polymer/decorators';
@@ -27,9 +25,7 @@
}
@customElement('gr-settings-item')
-class GrSettingsItem extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrSettingsItem extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
index e288d20..8a6c084 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/gr-page-nav-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-settings-menu-item_html';
import {property, customElement} from '@polymer/decorators';
@@ -28,9 +26,7 @@
}
@customElement('gr-settings-menu-item')
-class GrSettingsMenuItem extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrSettingsMenuItem extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 809139d..f9f7a93 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -42,8 +42,6 @@
import '../gr-menu-editor/gr-menu-editor';
import '../gr-ssh-editor/gr-ssh-editor';
import '../gr-watched-projects-editor/gr-watched-projects-editor';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-settings-view_html';
import {getDocsBaseUrl} from '../../../utils/url-util';
@@ -76,6 +74,7 @@
'email_strategy',
'diff_view',
'publish_comments_on_push',
+ 'disable_keyboard_shortcuts',
'work_in_progress_by_default',
'default_base_for_merges',
'signed_off_by',
@@ -114,14 +113,13 @@
workInProgressByDefault: HTMLInputElement;
showSizeBarsInFileList: HTMLInputElement;
publishCommentsOnPush: HTMLInputElement;
+ disableKeyboardShortcuts: HTMLInputElement;
relativeDateInChangeTable: HTMLInputElement;
};
}
@customElement('gr-settings-view')
-export class GrSettingsView extends ChangeTableMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrSettingsView extends ChangeTableMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -212,11 +210,11 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
// Polymer 2: anchor tag won't work on shadow DOM
// we need to manually calling scrollIntoView when hash changed
- this.listen(window, 'location-change', '_handleLocationChange');
+ window.addEventListener('location-change', this.handleLocationChange);
fireTitleChange(this, 'Settings');
this._isDark = !!window.localStorage.getItem('dark-theme');
@@ -296,16 +294,16 @@
this._loading = false;
// Handle anchor tag for initial load
- this._handleLocationChange();
+ this.handleLocationChange();
});
}
- detached() {
- super.detached();
- this.unlisten(window, 'location-change', '_handleLocationChange');
+ disconnectedCallback() {
+ window.removeEventListener('location-change', this.handleLocationChange);
+ super.disconnectedCallback();
}
- _handleLocationChange() {
+ private readonly handleLocationChange = () => {
// Handle anchor tag after dom attached
const urlHash = window.location.hash;
if (urlHash) {
@@ -315,7 +313,7 @@
elem.scrollIntoView();
}
}
- }
+ };
reloadAccountDetail() {
Promise.all([this.$.accountInfo.loadData(), this.$.emailEditor.loadData()]);
@@ -342,9 +340,7 @@
_cloneMenu(prefs: TopMenuItemInfo[]) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- return prefs.map(({id, ...item}) => {
- return item;
- });
+ return prefs.map(({id, ...item}) => item);
}
@observe('_localChangeTableColumns', '_showNumber')
@@ -384,6 +380,13 @@
);
}
+ _handleDisableKeyboardShortcutsChanged() {
+ this.set(
+ '_localPrefs.disable_keyboard_shortcuts',
+ this.$.disableKeyboardShortcuts.checked
+ );
+ }
+
_handleWorkInProgressByDefault() {
this.set(
'_localPrefs.work_in_progress_by_default',
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
index 11372a1..8b000e9 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
@@ -75,14 +75,10 @@
<li><a href="#HTTPCredentials">HTTP Credentials</a></li>
</template>
<li hidden$="[[!_serverConfig.sshd]]">
- <a href="#SSHKeys">
- SSH Keys
- </a>
+ <a href="#SSHKeys"> SSH Keys </a>
</li>
<li hidden$="[[!_serverConfig.receive.enable_signed_push]]">
- <a href="#GPGKeys">
- GPG Keys
- </a>
+ <a href="#GPGKeys"> GPG Keys </a>
</li>
<li><a href="#Groups">Groups</a></li>
<li><a href="#Identities">Identities</a></li>
@@ -107,7 +103,7 @@
aria-labelledby="darkThemeToggleLabel"
checked="[[_isDark]]"
on-change="_handleToggleDark"
- on-tap="_onTapDarkToggle"
+ on-click="_onTapDarkToggle"
></paper-toggle-button>
<div id="darkThemeToggleLabel">Dark theme (alpha)</div>
</div>
@@ -184,9 +180,9 @@
<select id="emailNotificationsSelect">
<option value="CC_ON_OWN_COMMENTS">Every comment</option>
<option value="ENABLED">Only comments left by others</option>
- <option value="ATTENTION_SET_ONLY"
- >Only when I am in the attention set</option
- >
+ <option value="ATTENTION_SET_ONLY">
+ Only when I am in the attention set
+ </option>
<option value="DISABLED">None</option>
</select>
</gr-select>
@@ -278,6 +274,19 @@
</span>
</section>
<section>
+ <label for="disableKeyboardShortcuts" class="title"
+ >Disable all keyboard shortcuts</label
+ >
+ <span class="value">
+ <input
+ id="disableKeyboardShortcuts"
+ type="checkbox"
+ checked$="[[_localPrefs.disable_keyboard_shortcuts]]"
+ on-change="_handleDisableKeyboardShortcutsChanged"
+ />
+ </span>
+ </section>
+ <section>
<label for="insertSignedOff" class="title">
Insert Signed-off-by Footer For Inline Edit Changes
</label>
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
index 98abb3fb..79789bb 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
@@ -329,7 +329,7 @@
test('emails are loaded without emailToken', () => {
sinon.stub(element.$.emailEditor, 'loadData');
element.params = {};
- element.attached();
+ element.connectedCallback();
assert.isTrue(element.$.emailEditor.loadData.calledOnce);
});
@@ -465,7 +465,7 @@
confirmEmailStub = stubRestApi('confirmEmail').returns(
new Promise(resolve => { resolveConfirm = resolve; }));
element.params = {view: GerritView.SETTINGS, emailToken: 'foo'};
- element.attached();
+ element.connectedCallback();
});
test('it is used to confirm email via rest API', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
index b30b2cb..c1f347f 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
@@ -21,8 +21,6 @@
import '../../shared/gr-overlay/gr-overlay';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-ssh-editor_html';
import {property, customElement} from '@polymer/decorators';
@@ -46,9 +44,7 @@
}
}
@customElement('gr-ssh-editor')
-export class GrSshEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrSshEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
index a45e160..6178e7a 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
@@ -20,8 +20,6 @@
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-watched-projects-editor_html';
import {customElement, property} from '@polymer/decorators';
@@ -49,9 +47,7 @@
};
}
@customElement('gr-watched-projects-editor')
-export class GrWatchedProjectsEditor extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrWatchedProjectsEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index 8ff7a3a..dab778b 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -18,8 +18,6 @@
import '../gr-button/gr-button';
import '../gr-icons/gr-icons';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-chip_html';
import {customElement, property} from '@polymer/decorators';
@@ -27,9 +25,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-account-chip')
-export class GrAccountChip extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountChip extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
index 4e6dd1a..e5efebb 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
display: block;
overflow: hidden;
@@ -42,7 +42,10 @@
}
gr-button.remove {
--gr-remove-button-style: {
- border: 0;
+ border-top-width: 0;
+ border-right-width: 0;
+ border-bottom-width: 0;
+ border-left-width: 0;
color: var(--deemphasized-text-color);
font-weight: var(--font-weight-normal);
height: 0.6em;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
index 2562a1a..d793a8d 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-entry/gr-account-entry.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../gr-autocomplete/gr-autocomplete';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-entry_html';
import {customElement, property} from '@polymer/decorators';
@@ -33,9 +31,7 @@
* and/or group with autocomplete support.
*/
@customElement('gr-account-entry')
-export class GrAccountEntry extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountEntry extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index 3f8fe6b..64bae58 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -18,8 +18,6 @@
import '../../../styles/shared-styles';
import '../gr-avatar/gr-avatar';
import '../gr-hovercard-account/gr-hovercard-account';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-label_html';
import {appContext} from '../../../services/app-context';
@@ -34,9 +32,7 @@
import {ShowAlertEventDetail} from '../../../types/events';
@customElement('gr-account-label')
-export class GrAccountLabel extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountLabel extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
index e287f79..ff40aeb 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
display: inline-block;
vertical-align: top;
@@ -72,10 +72,13 @@
vertical-align: top;
}
iron-icon.attention {
+ color: var(--deemphasized-text-color);
width: 12px;
height: 12px;
+ vertical-align: top;
}
iron-icon.status {
+ color: var(--deemphasized-text-color);
width: 14px;
height: 14px;
vertical-align: top;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
index e25bdea..f37aa01 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
@@ -29,7 +29,6 @@
}
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
element = basicFixture.instantiate();
element._config = {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
index be54f4e..5c4b76a 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
@@ -17,8 +17,6 @@
import '../gr-account-label/gr-account-label';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-link_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -26,9 +24,7 @@
import {AccountInfo, ChangeInfo} from '../../../types/common';
@customElement('gr-account-link')
-class GrAccountLink extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrAccountLink extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts
index be4db01..98a6e77 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
display: inline-block;
vertical-align: top;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.js b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.js
index af485c6..34fef2f 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.js
@@ -18,7 +18,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-account-link.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-account-link');
@@ -26,7 +25,6 @@
let element;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
index 5cc1240..1e54f69 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
@@ -17,8 +17,6 @@
import '../gr-account-chip/gr-account-chip';
import '../gr-account-entry/gr-account-entry';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-account-list_html';
import {appContext} from '../../../services/app-context';
@@ -115,9 +113,7 @@
}
@customElement('gr-account-list')
-export class GrAccountList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAccountList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -192,11 +188,6 @@
super();
this.reporting = appContext.reportingService;
this._querySuggestions = input => this._getSuggestions(input);
- }
-
- /** @override */
- created() {
- super.created();
this.addEventListener('remove', e =>
this._handleRemove(e as CustomEvent<{account: AccountInput}>)
);
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.js b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.js
index 6430290..20e8672 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.js
@@ -17,7 +17,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-account-list.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-account-list');
@@ -61,7 +60,6 @@
existingAccount1 = makeAccount();
existingAccount2 = makeAccount();
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
element.accounts = [existingAccount1, existingAccount2];
suggestionsProvider = new MockSuggestionsProvider();
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
index a0fddcd..4d2576a 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
@@ -16,8 +16,6 @@
*/
import '../gr-button/gr-button';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-alert_html';
import {getRootElement} from '../../../scripts/rootElement';
@@ -31,9 +29,7 @@
}
@customElement('gr-alert')
-export class GrAlert extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAlert extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -75,21 +71,21 @@
_actionCallback?: () => void;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._boundTransitionEndHandler = () => this._handleTransitionEnd();
this.addEventListener('transitionend', this._boundTransitionEndHandler);
}
/** @override */
- detached() {
- super.detached();
+ disconnectedCallback() {
if (this._boundTransitionEndHandler) {
this.removeEventListener(
'transitionend',
this._boundTransitionEndHandler
);
}
+ super.disconnectedCallback();
}
show(text: string, actionText?: string, actionCallback?: () => void) {
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_html.ts b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_html.ts
index b66a1dd..bc517a8 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_html.ts
@@ -27,7 +27,7 @@
bottom: 1.25rem;
border-radius: var(--border-radius);
box-shadow: var(--elevation-level-2);
- color: var(--view-background-color);
+ color: var(--tooltip-text-color);
left: 1.25rem;
position: fixed;
transform: translateY(5rem);
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
index aff6d50..fdc72ce 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
@@ -18,8 +18,6 @@
import '../gr-cursor-manager/gr-cursor-manager';
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-autocomplete-dropdown_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -31,7 +29,6 @@
export interface GrAutocompleteDropdown {
$: {
- cursor: GrCursorManager;
suggestions: Element;
};
}
@@ -50,14 +47,9 @@
value?: string;
}
-/**
- * @extends PolymerElement
- */
@customElement('gr-autocomplete-dropdown')
export class GrAutocompleteDropdown extends IronFitMixin(
- KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
- ),
+ KeyboardShortcutMixin(PolymerElement),
IronFitBehavior as IronFitBehavior
) {
static get template() {
@@ -91,9 +83,6 @@
@property({type: Array})
suggestions: Item[] = [];
- @property({type: Array})
- _suggestionEls: Element[] = [];
-
get keyBindings() {
return {
up: '_handleUp',
@@ -104,6 +93,20 @@
};
}
+ private cursor = new GrCursorManager();
+
+ constructor() {
+ super();
+ this.cursor.cursorTargetClass = 'selected';
+ this.cursor.focusOnMove = true;
+ }
+
+ /** @override */
+ disconnectedCallback() {
+ this.cursor.unsetCursor();
+ super.disconnectedCallback();
+ }
+
close() {
this.isHidden = true;
}
@@ -137,13 +140,13 @@
cursorDown() {
if (!this.isHidden) {
- this.$.cursor.next();
+ this.cursor.next();
}
}
cursorUp() {
if (!this.isHidden) {
- this.$.cursor.previous();
+ this.cursor.previous();
}
}
@@ -154,7 +157,7 @@
new CustomEvent('item-selected', {
detail: {
trigger: 'tab',
- selected: this.$.cursor.target,
+ selected: this.cursor.target,
},
composed: true,
bubbles: true,
@@ -169,7 +172,7 @@
new CustomEvent('item-selected', {
detail: {
trigger: 'enter',
- selected: this.$.cursor.target,
+ selected: this.cursor.target,
},
composed: true,
bubbles: true,
@@ -209,7 +212,7 @@
}
getCursorTarget() {
- return this.$.cursor.target;
+ return this.cursor.target;
}
@observe('suggestions')
@@ -217,18 +220,23 @@
if (this.suggestions.length > 0) {
if (!this.isHidden) {
flush();
- this._suggestionEls = Array.from(
+ this.cursor.stops = Array.from(
this.$.suggestions.querySelectorAll('li')
);
this._resetCursorIndex();
}
} else {
- this._suggestionEls = [];
+ this.cursor.stops = [];
}
}
+ @observe('index')
+ _setIndex() {
+ this.cursor.index = this.index || -1;
+ }
+
_resetCursorIndex() {
- this.$.cursor.setCursorAtIndex(0);
+ this.cursor.setCursorAtIndex(0);
}
_computeLabelClass(item: Item) {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.ts
index d3d2481..b86e8ec 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_html.ts
@@ -91,12 +91,4 @@
</template>
</ul>
</div>
- <gr-cursor-manager
- id="cursor"
- index="{{index}}"
- cursor-target-class="selected"
- scroll-mode="never"
- focus-on-move=""
- stops="[[_suggestionEls]]"
- ></gr-cursor-manager>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.js b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.js
index ad06649..200fddc 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.js
@@ -55,7 +55,7 @@
element.addEventListener('item-selected', itemSelectedStub);
MockInteractions.pressAndReleaseKeyOn(element, 9);
assert.isTrue(handleTabSpy.called);
- assert.equal(element.$.cursor.index, 0);
+ assert.equal(element.cursor.index, 0);
assert.isTrue(itemSelectedStub.called);
assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, {
trigger: 'tab',
@@ -69,7 +69,7 @@
element.addEventListener('item-selected', itemSelectedStub);
MockInteractions.pressAndReleaseKeyOn(element, 13);
assert.isTrue(handleEnterSpy.called);
- assert.equal(element.$.cursor.index, 0);
+ assert.equal(element.cursor.index, 0);
assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, {
trigger: 'enter',
selected: element.getCursorTarget(),
@@ -78,28 +78,28 @@
test('down key', () => {
element.isHidden = true;
- const nextSpy = sinon.spy(element.$.cursor, 'next');
+ const nextSpy = sinon.spy(element.cursor, 'next');
MockInteractions.pressAndReleaseKeyOn(element, 40);
assert.isFalse(nextSpy.called);
- assert.equal(element.$.cursor.index, 0);
+ assert.equal(element.cursor.index, 0);
element.isHidden = false;
MockInteractions.pressAndReleaseKeyOn(element, 40);
assert.isTrue(nextSpy.called);
- assert.equal(element.$.cursor.index, 1);
+ assert.equal(element.cursor.index, 1);
});
test('up key', () => {
element.isHidden = true;
- const prevSpy = sinon.spy(element.$.cursor, 'previous');
+ const prevSpy = sinon.spy(element.cursor, 'previous');
MockInteractions.pressAndReleaseKeyOn(element, 38);
assert.isFalse(prevSpy.called);
- assert.equal(element.$.cursor.index, 0);
+ assert.equal(element.cursor.index, 0);
element.isHidden = false;
- element.$.cursor.setCursorAtIndex(1);
- assert.equal(element.$.cursor.index, 1);
+ element.cursor.setCursorAtIndex(1);
+ assert.equal(element.cursor.index, 1);
MockInteractions.pressAndReleaseKeyOn(element, 38);
assert.isTrue(prevSpy.called);
- assert.equal(element.$.cursor.index, 0);
+ assert.equal(element.cursor.index, 0);
});
test('tapping selects item', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index f4eb053..1ff5350 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -20,17 +20,15 @@
import '../gr-icons/gr-icons';
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-autocomplete_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {property, customElement, observe} from '@polymer/decorators';
import {GrAutocompleteDropdown} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
-import {GrCursorManager} from '../gr-cursor-manager/gr-cursor-manager';
import {PaperInputElementExt} from '../../../types/types';
import {CustomKeyboardEvent} from '../../../types/events';
import {fireEvent} from '../../../utils/event-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
const DEBOUNCE_WAIT_MS = 200;
@@ -39,7 +37,6 @@
$: {
input: PaperInputElementExt;
suggestions: GrAutocompleteDropdown;
- cursor: GrCursorManager;
};
}
@@ -64,16 +61,10 @@
value: string;
}
-export type AutocompleteCommitEvent = CustomEvent<
- AutocompleteCommitEventDetail
->;
-
-const DEBOUNCER_UPDATE_SUGGESTIONS = 'update-suggestions';
+export type AutocompleteCommitEvent = CustomEvent<AutocompleteCommitEventDetail>;
@customElement('gr-autocomplete')
-export class GrAutocomplete extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrAutocomplete extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -203,6 +194,8 @@
@property({type: Object})
_selected: HTMLElement | null = null;
+ private updateSuggestionsTask?: DelayedTask;
+
get _nativeInput() {
// In Polymer 2 inputElement isn't nativeInput anymore
return (this.$.input.$.nativeInput ||
@@ -210,16 +203,16 @@
}
/** @override */
- attached() {
- super.attached();
- this.listen(document.body, 'click', '_handleBodyClick');
+ connectedCallback() {
+ super.connectedCallback();
+ document.addEventListener('click', this.handleBodyClick);
}
/** @override */
- detached() {
- super.detached();
- this.unlisten(document.body, 'click', '_handleBodyClick');
- this.cancelDebouncer(DEBOUNCER_UPDATE_SUGGESTIONS);
+ disconnectedCallback() {
+ document.removeEventListener('click', this.handleBodyClick);
+ this.updateSuggestionsTask?.cancel();
+ super.disconnectedCallback();
}
get focusStart() {
@@ -332,7 +325,11 @@
if (noDebounce) {
update();
} else {
- this.debounce(DEBOUNCER_UPDATE_SUGGESTIONS, update, DEBOUNCE_WAIT_MS);
+ this.updateSuggestionsTask = debounce(
+ this.updateSuggestionsTask,
+ update,
+ DEBOUNCE_WAIT_MS
+ );
}
}
@@ -445,7 +442,7 @@
}
}
- _handleBodyClick(e: Event) {
+ private readonly handleBodyClick = (e: Event) => {
const eventPath = e.composedPath();
if (!eventPath) return;
for (let i = 0; i < eventPath.length; i++) {
@@ -454,7 +451,7 @@
}
}
this._focused = false;
- }
+ };
/**
* Commits the suggestion, optionally firing the commit event.
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.js
index 329265e..d72007e 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.js
@@ -46,7 +46,7 @@
]));
element.query = queryStub;
assert.isTrue(element.$.suggestions.isHidden);
- assert.equal(element.$.suggestions.$.cursor.index, -1);
+ assert.equal(element.$.suggestions.cursor.index, -1);
focusOnInput(element);
element.text = 'blah';
@@ -64,7 +64,7 @@
assert.equal(suggestions[i].innerText.trim(), 'blah ' + i);
}
- assert.notEqual(element.$.suggestions.$.cursor.index, -1);
+ assert.notEqual(element.$.suggestions.cursor.index, -1);
});
});
@@ -121,7 +121,7 @@
element.query = queryStub;
assert.isTrue(element.$.suggestions.isHidden);
- assert.equal(element.$.suggestions.$.cursor.index, -1);
+ assert.equal(element.$.suggestions.cursor.index, -1);
element._focused = true;
element.text = 'blah';
@@ -131,21 +131,21 @@
const commitHandler = sinon.spy();
element.addEventListener('commit', commitHandler);
- assert.equal(element.$.suggestions.$.cursor.index, 0);
+ assert.equal(element.$.suggestions.cursor.index, 0);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
'down');
- assert.equal(element.$.suggestions.$.cursor.index, 1);
+ assert.equal(element.$.suggestions.cursor.index, 1);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
'down');
- assert.equal(element.$.suggestions.$.cursor.index, 2);
+ assert.equal(element.$.suggestions.cursor.index, 2);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 38, null, 'up');
- assert.equal(element.$.suggestions.$.cursor.index, 1);
+ assert.equal(element.$.suggestions.cursor.index, 1);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
'enter');
@@ -215,19 +215,18 @@
});
test('noDebounce=false debounces the query', () => {
+ const clock = sinon.useFakeTimers();
const queryStub = sinon.spy(() => Promise.resolve([]));
- let callback;
- const debounceStub = sinon.stub(element, 'debounce').callsFake(
- (name, cb) => { callback = cb; });
element.query = queryStub;
element.noDebounce = false;
focusOnInput(element);
element.text = 'a';
+
+ // not called right away
assert.isFalse(queryStub.called);
- assert.isTrue(debounceStub.called);
- assert.equal(debounceStub.lastCall.args[2], 200);
- assert.isFunction(callback);
- callback();
+
+ // but called after a while
+ clock.tick(1000);
assert.isTrue(queryStub.called);
});
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index 9d7e19b..e30e995 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-avatar_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -26,9 +24,7 @@
import {appContext} from '../../../services/app-context';
@customElement('gr-avatar')
-export class GrAvatar extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrAvatar extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -45,8 +41,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
Promise.all([
this._getConfig(),
getPluginLoader().awaitPluginsLoaded(),
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
index e55c8f1..a1e51df 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
display: inline-block;
border-radius: 50%;
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
index 0eef5a7..df8632f 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
@@ -103,9 +103,9 @@
suite('config set', () => {
setup(() => {
- stub('gr-avatar', {
- _getConfig: () => Promise.resolve({plugin: {has_avatars: true}}),
- });
+ stub('gr-avatar', '_getConfig').callsFake(() =>
+ Promise.resolve({plugin: {has_avatars: true}})
+ );
element = basicFixture.instantiate();
});
@@ -141,9 +141,9 @@
let element;
setup(() => {
- stub('gr-avatar', {
- _getConfig: () => Promise.resolve({plugin: {has_avatars: true}}),
- });
+ stub('gr-avatar', '_getConfig').callsFake(() =>
+ Promise.resolve({plugin: {has_avatars: true}})
+ );
element = basicFixture.instantiate();
});
@@ -169,9 +169,7 @@
let element;
setup(() => {
- stub('gr-avatar', {
- _getConfig: () => Promise.resolve({}),
- });
+ stub('gr-avatar', '_getConfig').callsFake(() => Promise.resolve({}));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
index 60b891e..6a7c05b 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
@@ -16,8 +16,6 @@
*/
import '@polymer/paper-button/paper-button';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property, computed, observe} from '@polymer/decorators';
import {htmlTemplate} from './gr-button_html';
@@ -35,8 +33,8 @@
}
@customElement('gr-button')
-export class GrButton extends LegacyElementMixin(
- KeyboardShortcutMixin(TooltipMixin(GestureEventListeners(PolymerElement)))
+export class GrButton extends KeyboardShortcutMixin(
+ TooltipMixin(PolymerElement)
) {
static get template() {
return htmlTemplate;
@@ -83,9 +81,8 @@
private readonly reporting: ReportingService = appContext.reportingService;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this._initialTabindex = this.getAttribute('tabindex') || '0';
// TODO(TS): try avoid using unknown
this.addEventListener('click', e =>
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts
index b272951..4d94a98 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
/* general styles for all buttons */
:host {
--background-color: var(
@@ -53,7 +53,10 @@
font: inherit;
text-transform: uppercase;
outline-width: 0;
- border-radius: var(--border-radius);
+ border-top-left-radius: var(--border-radius);
+ border-top-right-radius: var(--border-radius);
+ border-bottom-right-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.js b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
similarity index 69%
rename from polygerrit-ui/app/elements/shared/gr-button/gr-button_test.js
rename to polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
index 242cb28..f0f122a 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
@@ -15,18 +15,21 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-button.js';
-import {addListener} from '@polymer/polymer/lib/utils/gestures.js';
-import {appContext} from '../../../services/app-context.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import '../../../test/common-test-setup-karma';
+import {addListener} from '@polymer/polymer/lib/utils/gestures';
+import {appContext} from '../../../services/app-context';
+import {html} from '@polymer/polymer/lib/utils/html-tag';
+import {GrButton} from './gr-button';
+import {queryAndAssert} from '../../../test/test-utils';
+import {PaperButtonElement} from '@polymer/paper-button';
const basicFixture = fixtureFromElement('gr-button');
const nestedFixture = fixtureFromTemplate(html`
-<div id="test">
- <gr-button class="testBtn"></gr-button>
-</div>
+ <div id="test">
+ <gr-button class="testBtn"></gr-button>
+ </div>
`);
const tabindexFixture = fixtureFromTemplate(html`
@@ -34,11 +37,11 @@
`);
suite('gr-button tests', () => {
- let element;
+ let element: GrButton;
- const addSpyOn = function(eventName) {
+ const addSpyOn = function (eventName: string) {
const spy = sinon.spy();
- if (eventName == 'tap') {
+ if (eventName === 'tap') {
addListener(element, eventName, spy);
} else {
element.addEventListener(eventName, spy);
@@ -51,7 +54,10 @@
});
test('disabled is set by disabled', () => {
- const paperBtn = element.shadowRoot.querySelector('paper-button');
+ const paperBtn = queryAndAssert<PaperButtonElement>(
+ element,
+ 'paper-button'
+ );
assert.isFalse(paperBtn.disabled);
element.disabled = true;
assert.isTrue(paperBtn.disabled);
@@ -60,17 +66,21 @@
});
test('loading set from listener', () => {
- let resolve;
+ let resolve: Function;
element.addEventListener('click', e => {
- e.target.loading = true;
- resolve = () => e.target.loading = false;
+ const target = e.target as HTMLElement;
+ target.setAttribute('loading', 'true');
+ resolve = () => target.removeAttribute('loading');
});
- const paperBtn = element.shadowRoot.querySelector('paper-button');
+ const paperBtn = queryAndAssert<PaperButtonElement>(
+ element,
+ 'paper-button'
+ );
assert.isFalse(paperBtn.disabled);
MockInteractions.tap(element);
assert.isTrue(paperBtn.disabled);
assert.isTrue(element.hasAttribute('loading'));
- resolve();
+ resolve!();
flush();
assert.isFalse(paperBtn.disabled);
assert.isFalse(element.hasAttribute('loading'));
@@ -92,13 +102,13 @@
});
test('tabindex should be preserved', () => {
- element = tabindexFixture.instantiate();
- element.disabled = false;
- assert.equal(element.getAttribute('tabindex'), '3');
- element.disabled = true;
- assert.equal(element.getAttribute('tabindex'), '-1');
- element.disabled = false;
- assert.equal(element.getAttribute('tabindex'), '3');
+ const tabIndexElement = tabindexFixture.instantiate() as GrButton;
+ tabIndexElement.disabled = false;
+ assert.equal(tabIndexElement.getAttribute('tabindex'), '3');
+ tabIndexElement.disabled = true;
+ assert.equal(tabIndexElement.getAttribute('tabindex'), '-1');
+ tabIndexElement.disabled = false;
+ assert.equal(tabIndexElement.getAttribute('tabindex'), '3');
});
// 'tap' event is tested so we don't loose backward compatibility with older
@@ -123,14 +133,14 @@
// Keycodes: 32 for Space, 13 for Enter.
for (const key of [32, 13]) {
- test('dispatches click event on keycode ' + key, () => {
+ test(`dispatches click event on keycode ${key}`, () => {
const tapSpy = sinon.spy();
element.addEventListener('click', tapSpy);
MockInteractions.pressAndReleaseKeyOn(element, key);
assert.isTrue(tapSpy.calledOnce);
});
- test('dispatches no click event with modifier on keycode ' + key, () => {
+ test(`dispatches no click event with modifier on keycode ${key}`, () => {
const tapSpy = sinon.spy();
element.addEventListener('click', tapSpy);
MockInteractions.pressAndReleaseKeyOn(element, key, 'shift');
@@ -156,7 +166,7 @@
// Keycodes: 32 for Space, 13 for Enter.
for (const key of [32, 13]) {
- test('stops click event on keycode ' + key, () => {
+ test(`stops click event on keycode ${key}`, () => {
const tapSpy = sinon.spy();
element.addEventListener('click', tapSpy);
MockInteractions.pressAndReleaseKeyOn(element, key);
@@ -166,10 +176,9 @@
});
suite('reporting', () => {
- let reportStub;
+ let reportStub: sinon.SinonStub;
setup(() => {
- reportStub = sinon.stub(appContext.reportingService,
- 'reportInteraction');
+ reportStub = sinon.stub(appContext.reportingService, 'reportInteraction');
reportStub.reset();
});
@@ -178,20 +187,20 @@
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'button-click');
assert.deepEqual(reportStub.lastCall.args[1], {
- path: `html>body>test-fixture#${basicFixture.fixtureId}>gr-button`,
+ path: `html>body>test-fixture#${element.parentElement!.id}>gr-button`,
});
});
test('report event after click on nested', () => {
- element = nestedFixture.instantiate();
- MockInteractions.click(element.querySelector('gr-button'));
+ const nestedElement = nestedFixture.instantiate() as HTMLDivElement;
+ MockInteractions.click(queryAndAssert(nestedElement, 'gr-button'));
assert.isTrue(reportStub.calledOnce);
assert.equal(reportStub.lastCall.args[0], 'button-click');
assert.deepEqual(reportStub.lastCall.args[1], {
- path: `html>body>test-fixture#${nestedFixture.fixtureId}` +
- `>div#test>gr-button.testBtn`,
+ path:
+ `html>body>test-fixture#${nestedElement.parentElement!.id}` +
+ '>div#test>gr-button.testBtn',
});
});
});
});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
index 1ecaf7f..2b66af8 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
@@ -16,13 +16,12 @@
*/
import '../gr-icons/gr-icons';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-star_html';
import {customElement, property} from '@polymer/decorators';
import {ChangeInfo} from '../../../types/common';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
+import {fireAlert} from '../../../utils/event-util';
declare global {
interface HTMLElementTagNameMap {
@@ -36,9 +35,7 @@
}
@customElement('gr-change-star')
-export class GrChangeStar extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrChangeStar extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -78,6 +75,7 @@
change: this.change,
starred: newVal,
};
+ if (newVal) fireAlert(this, 'Starring change...');
this.dispatchEvent(
new CustomEvent('toggle-star', {
bubbles: true,
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.js b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.js
deleted file mode 100644
index f05ed21..0000000
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-change-star.js';
-
-const basicFixture = fixtureFromElement('gr-change-star');
-
-suite('gr-change-star tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- element.change = {
- _number: 2,
- starred: true,
- };
- });
-
- test('star visibility states', () => {
- element.set('change.starred', true);
- let icon = element.shadowRoot
- .querySelector('iron-icon');
- assert.isTrue(icon.classList.contains('active'));
- assert.equal(icon.icon, 'gr-icons:star');
-
- element.set('change.starred', false);
- icon = element.shadowRoot
- .querySelector('iron-icon');
- assert.isFalse(icon.classList.contains('active'));
- assert.equal(icon.icon, 'gr-icons:star-border');
- });
-
- test('starring', async () => {
- let resolve;
- const promise = new Promise(r => resolve = r);
- element.addEventListener('toggle-star', resolve);
- element.set('change.starred', false);
- MockInteractions.tap(element.shadowRoot
- .querySelector('button'));
-
- await promise;
- assert.equal(element.change.starred, true);
- });
-
- test('unstarring', async () => {
- let resolve;
- const promise = new Promise(r => resolve = r);
- element.addEventListener('toggle-star', resolve);
- element.set('change.starred', true);
- MockInteractions.tap(element.shadowRoot
- .querySelector('button'));
-
- await promise;
- assert.equal(element.change.starred, false);
- });
-});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.ts
new file mode 100644
index 0000000..8f411ae
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.ts
@@ -0,0 +1,71 @@
+/**
+ * @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.
+ */
+
+import {IronIconElement} from '@polymer/iron-icon';
+import '../../../test/common-test-setup-karma';
+import {queryAndAssert} from '../../../test/test-utils';
+import {GrChangeStar} from './gr-change-star';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import {createChange} from '../../../test/test-data-generators';
+
+const basicFixture = fixtureFromElement('gr-change-star');
+
+suite('gr-change-star tests', () => {
+ let element: GrChangeStar;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ element.change = {
+ ...createChange(),
+ starred: true,
+ };
+ });
+
+ test('star visibility states', async () => {
+ element.set('change.starred', true);
+ await flush();
+ let icon = queryAndAssert<IronIconElement>(element, 'iron-icon');
+ assert.isTrue(icon.classList.contains('active'));
+ assert.equal(icon.icon, 'gr-icons:star');
+
+ element.set('change.starred', false);
+ await flush();
+ icon = queryAndAssert<IronIconElement>(element, 'iron-icon');
+ assert.isFalse(icon.classList.contains('active'));
+ assert.equal(icon.icon, 'gr-icons:star-border');
+ });
+
+ test('starring', async () => {
+ element.set('change.starred', false);
+ await flush();
+ assert.equal(element.change!.starred, false);
+
+ MockInteractions.tap(queryAndAssert(element, 'button'));
+ await flush();
+ assert.equal(element.change!.starred, true);
+ });
+
+ test('unstarring', async () => {
+ element.set('change.starred', true);
+ await flush();
+ assert.equal(element.change!.starred, true);
+
+ MockInteractions.tap(queryAndAssert(element, 'button'));
+ await flush();
+ assert.equal(element.change!.starred, false);
+ });
+});
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
index 7cf9bb1..f18f121 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
@@ -16,11 +16,13 @@
*/
import '../gr-tooltip-content/gr-tooltip-content';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-status_html';
import {customElement, property} from '@polymer/decorators';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {getRevertCommitHash} from '../../../utils/message-util';
+import {ChangeInfo} from '../../../types/common';
+import {ParsedChangeInfo} from '../../../types/types';
enum ChangeStates {
MERGED = 'Merged',
@@ -28,6 +30,7 @@
MERGE_CONFLICT = 'Merge Conflict',
WIP = 'WIP',
PRIVATE = 'Private',
+ REVERT_CREATED = 'Revert Created',
}
const WIP_TOOLTIP =
@@ -44,11 +47,8 @@
'This change is only visible to its owner and ' +
'current reviewers (or anyone with "View Private Changes" permission).';
-/** @extends PolymerElement */
@customElement('gr-change-status')
-class GrChangeStatus extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrChangeStatus extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -56,6 +56,9 @@
@property({type: Boolean, reflectToAttribute: true})
flat = false;
+ @property({type: Object})
+ change?: ChangeInfo | ParsedChangeInfo;
+
@property({type: String, observer: '_updateChipDetails'})
status?: ChangeStates;
@@ -73,6 +76,17 @@
return str ? str.toLowerCase().replace(/\s/g, '-') : '';
}
+ hasStatusLink(status: ChangeStates) {
+ return status === ChangeStates.REVERT_CREATED;
+ }
+
+ getStatusLink(change?: ParsedChangeInfo) {
+ if (!change) return;
+ const revertCommit = getRevertCommitHash(change.messages);
+ if (!revertCommit) return;
+ return GerritNav.getUrlForSearchQuery(revertCommit);
+ }
+
_updateChipDetails(status?: ChangeStates, previousStatus?: ChangeStates) {
if (previousStatus) {
this.classList.remove(this._toClassName(previousStatus));
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
index 542d8be..379c3f3 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
@@ -52,6 +52,13 @@
background-color: var(--status-ready);
color: var(--status-ready);
}
+ :host(.revert-created) .chip {
+ background-color: var(--status-revert-created);
+ color: var(--status-revert-created);
+ }
+ .status-link {
+ text-decoration: none;
+ }
:host(.custom) .chip {
background-color: var(--status-custom);
color: var(--status-custom);
@@ -70,8 +77,17 @@
title="[[tooltipText]]"
max-width="40em"
>
- <div class="chip" aria-label$="Label: [[status]]">
- [[_computeStatusString(status)]]
- </div>
+ <template is="dom-if" if="[[hasStatusLink(status)]]">
+ <a class="status-link" href="[[getStatusLink(change)]]">
+ <div class="chip" aria-label$="Label: [[status]]">
+ [[_computeStatusString(status)]]
+ </div>
+ </a>
+ </template>
+ <template is="dom-if" if="[[!hasStatusLink(status)]]">
+ <div class="chip" aria-label$="Label: [[status]]">
+ [[_computeStatusString(status)]]
+ </div>
+ </template>
</gr-tooltip-content>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
index 16fc664..4ef97c9 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
@@ -37,6 +37,7 @@
test('WIP', () => {
element.status = 'WIP';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, 'Work in Progress');
assert.equal(element.tooltipText, WIP_TOOLTIP);
@@ -46,6 +47,7 @@
test('WIP flat', () => {
element.flat = true;
element.status = 'WIP';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, 'WIP');
assert.isDefined(element.tooltipText);
@@ -55,6 +57,7 @@
test('merged', () => {
element.status = 'Merged';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, '');
@@ -63,6 +66,7 @@
test('abandoned', () => {
element.status = 'Abandoned';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, '');
@@ -71,6 +75,7 @@
test('merge conflict', () => {
element.status = 'Merge Conflict';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, MERGE_CONFLICT_TOOLTIP);
@@ -79,6 +84,7 @@
test('private', () => {
element.status = 'Private';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, PRIVATE_TOOLTIP);
@@ -87,6 +93,7 @@
test('active', () => {
element.status = 'Active';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, '');
@@ -95,6 +102,7 @@
test('ready to submit', () => {
element.status = 'Ready to submit';
+ flush();
assert.equal(element.shadowRoot
.querySelector('.chip').innerText, element.status);
assert.equal(element.tooltipText, '');
@@ -103,10 +111,12 @@
test('updating status removes the previous class', () => {
element.status = 'Private';
+ flush();
assert.isTrue(element.classList.contains('private'));
assert.isFalse(element.classList.contains('wip'));
element.status = 'WIP';
+ flush();
assert.isFalse(element.classList.contains('private'));
assert.isTrue(element.classList.contains('wip'));
});
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index a5b7df7..5b70cb4 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -15,12 +15,9 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import '../gr-storage/gr-storage';
import '../gr-comment/gr-comment';
import '../../diff/gr-diff/gr-diff';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-comment-thread_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -53,7 +50,6 @@
} from '../../../types/common';
import {GrComment} from '../gr-comment/gr-comment';
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
-import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
import {CustomKeyboardEvent} from '../../../types/events';
import {LineNumber, FILE} from '../../diff/gr-diff/gr-diff-line';
import {GrButton} from '../gr-button/gr-button';
@@ -61,6 +57,9 @@
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {RenderPreferences} from '../../../api/diff';
import {check, assertIsDefined} from '../../../utils/common-util';
+import {waitForEventOnce} from '../../../utils/event-util';
+import {GrSyntaxLayer} from '../../diff/gr-syntax-layer/gr-syntax-layer';
+import {StorageLocation} from '../../../services/storage/gr-storage';
const UNRESOLVED_EXPAND_COUNT = 5;
const NEWLINE_PATTERN = /\n/g;
@@ -73,9 +72,7 @@
}
@customElement('gr-comment-thread')
-export class GrCommentThread extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrCommentThread extends KeyboardShortcutMixin(PolymerElement) {
// KeyboardShortcutMixin Not used in this element rather other elements tests
static get template() {
@@ -182,6 +179,8 @@
_renderPrefs: RenderPreferences = {
hide_left_side: true,
disable_context_control_buttons: true,
+ show_file_comment_button: false,
+ hide_line_length_indicator: true,
};
@property({type: Boolean, reflectToAttribute: true})
@@ -209,7 +208,9 @@
flagsService = appContext.flagsService;
- readonly storage = new GrStorage();
+ readonly storage = appContext.storageService;
+
+ private readonly syntaxLayer = new GrSyntaxLayer();
private isCommentContextExperimentEnabled = this.flagsService.isEnabled(
KnownExperimentId.COMMENT_CONTEXT
@@ -217,17 +218,16 @@
readonly restApiService = appContext.restApiService;
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('comment-update', e =>
this._handleCommentUpdate(e as CustomEvent)
);
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getLoggedIn().then(loggedIn => {
this._showActions = loggedIn;
});
@@ -235,11 +235,11 @@
if (!prefs) return;
this._prefs = {
...prefs,
- show_file_comment_button: false,
- // override explicitly so that diff doesn't take too much width
- // compared to the context
- line_wrapping: false,
+ // set line_wrapping to true so that the context can take all the
+ // remaining space after comment card has rendered
+ line_wrapping: true,
};
+ this.syntaxLayer.setEnabled(!!prefs.syntax_highlighting);
});
this._setInitialExpandedState();
}
@@ -248,7 +248,16 @@
get _diff() {
if (this.comments === undefined || this.path === undefined) return;
if (!this.comments[0]?.context_lines?.length) return;
- return computeDiffFromContext(this.comments[0].context_lines, this.path);
+ waitForEventOnce(this, 'render').then(() => {
+ this.syntaxLayer.process();
+ });
+ const diff = computeDiffFromContext(
+ this.comments[0].context_lines,
+ this.path,
+ this.comments[0].source_content_type
+ );
+ this.syntaxLayer.init(diff);
+ return diff;
}
_shouldShowCommentContext(diff?: DiffInfo) {
@@ -333,6 +342,11 @@
return undefined;
}
+ _getLayers(diff?: DiffInfo) {
+ if (!diff) return [];
+ return [this.syntaxLayer];
+ }
+
_getUrlForViewDiff(comments: UIComment[]) {
assertIsDefined(this.changeNum, 'changeNum');
assertIsDefined(this.projectName, 'projectName');
@@ -504,7 +518,7 @@
if (!isEditing) {
// Allow the reply to render in the dom-repeat.
- this.async(() => {
+ setTimeout(() => {
const commentEl = this._commentElWithDraftID(reply.__draftID);
if (commentEl) commentEl.save();
}, 1);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
index 55408c0..a1644e7 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
@@ -47,6 +47,7 @@
color: var(--comment-text-color);
box-shadow: var(--elevation-level-2);
border-radius: var(--border-radius);
+ flex-shrink: 0;
}
#container {
display: var(--gr-comment-thread-display, flex);
@@ -86,15 +87,24 @@
.fileName {
padding: var(--spacing-m) var(--spacing-s) var(--spacing-m);
}
+ @media only screen and (max-width: 1200px) {
+ .diff-container {
+ display: none;
+ }
+ }
.diff-container {
margin-left: var(--spacing-l);
border: 1px solid var(--border-color);
- }
- .view-diff-container {
- text-align: end;
+ flex-grow: 1;
+ flex-shrink: 1;
+ max-width: 1200px;
}
.view-diff-button {
- margin: var(--spacing-m);
+ margin: var(--spacing-s) var(--spacing-m);
+ }
+ .view-diff-container {
+ border-top: 1px solid var(--border-color);
+ background-color: var(--background-color-primary);
}
</style>
@@ -193,6 +203,7 @@
id="diff"
change-num="[[changeNum]]"
diff="[[_diff]]"
+ layers="[[_getLayers(_diff)]]"
path="[[path]]"
prefs="[[_prefs]]"
render-prefs="[[_renderPrefs]]"
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
index f2df89d..64f5ad8 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
@@ -15,18 +15,18 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-comment-thread.js';
-import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {SpecialFilePath, Side} from '../../../constants/constants.js';
+import '../../../test/common-test-setup-karma';
+import './gr-comment-thread';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {SpecialFilePath, Side} from '../../../constants/constants';
import {
sortComments,
UIComment,
UIRobot,
isDraft,
UIDraft,
-} from '../../../utils/comment-util.js';
-import {GrCommentThread} from './gr-comment-thread.js';
+} from '../../../utils/comment-util';
+import {GrCommentThread} from './gr-comment-thread';
import {
PatchSetNum,
NumericChangeId,
@@ -37,15 +37,15 @@
RepoName,
ConfigInfo,
EmailAddress,
-} from '../../../types/common.js';
-import {GrComment} from '../gr-comment/gr-comment.js';
-import {LineNumber} from '../../diff/gr-diff/gr-diff-line.js';
+} from '../../../types/common';
+import {GrComment} from '../gr-comment/gr-comment';
+import {LineNumber} from '../../diff/gr-diff/gr-diff-line';
import {
tap,
pressAndReleaseKeyOn,
} from '@polymer/iron-test-helpers/mock-interactions';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-import {stubRestApi} from '../../../test/test-utils';
+import {stubRestApi, stubStorage} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-comment-thread');
@@ -156,9 +156,7 @@
];
const commentElStub = sinon
.stub(element, '_commentElWithDraftID')
- .callsFake(() => {
- return new GrComment();
- });
+ .callsFake(() => new GrComment());
const addDraftStub = sinon.stub(element, 'addDraft');
element.addOrEditDraft(123);
@@ -171,9 +169,7 @@
element.comments = [];
const commentElStub = sinon
.stub(element, '_commentElWithDraftID')
- .callsFake(() => {
- return new GrComment();
- });
+ .callsFake(() => new GrComment());
const addDraftStub = sinon.stub(element, 'addDraft');
element.addOrEditDraft(123);
@@ -652,7 +648,7 @@
__draft: true,
},
];
- const storageStub = sinon.stub(element.storage, 'setDraftComment');
+ const storageStub = stubStorage('setDraftComment');
flush();
const draftEl = element.root?.querySelectorAll('gr-comment')[1];
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index bf376f6..b7f1bcc 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -24,14 +24,11 @@
import '../gr-formatted-text/gr-formatted-text';
import '../gr-icons/gr-icons';
import '../gr-overlay/gr-overlay';
-import '../gr-storage/gr-storage';
import '../gr-textarea/gr-textarea';
import '../gr-tooltip-content/gr-tooltip-content';
import '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
import '../gr-account-label/gr-account-label';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-comment_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -40,7 +37,6 @@
import {customElement, observe, property} from '@polymer/decorators';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {GrTextarea} from '../gr-textarea/gr-textarea';
-import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
import {GrOverlay} from '../gr-overlay/gr-overlay';
import {
AccountDetailInfo,
@@ -48,6 +44,7 @@
ConfigInfo,
PatchSetNum,
RepoName,
+ BasePatchSetNum,
} from '../../../types/common';
import {GrButton} from '../gr-button/gr-button';
import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
@@ -62,6 +59,8 @@
import {fireAlert} from '../../../utils/event-util';
import {pluralize} from '../../../utils/string-util';
import {assertIsDefined} from '../../../utils/common-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {StorageLocation} from '../../../services/storage/gr-storage';
const STORAGE_DEBOUNCE_INTERVAL = 400;
const TOAST_DEBOUNCE_INTERVAL = 200;
@@ -101,16 +100,8 @@
};
}
-const DEBOUNCER_FIRE_UPDATE = 'fire-update';
-
-const DEBOUNCER_STORE = 'store';
-
-const DEBOUNCER_DRAFT_TOAST = 'draft-toast';
-
@customElement('gr-comment')
-export class GrComment extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrComment extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -277,13 +268,19 @@
private readonly restApiService = appContext.restApiService;
- private readonly storage = new GrStorage();
+ private readonly storage = appContext.storageService;
reporting = appContext.reportingService;
+ private fireUpdateTask?: DelayedTask;
+
+ private storeTask?: DelayedTask;
+
+ private draftToastTask?: DelayedTask;
+
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.restApiService.getAccount().then(account => {
this._selfAccount = account;
});
@@ -298,14 +295,14 @@
}
/** @override */
- detached() {
- super.detached();
- this.cancelDebouncer(DEBOUNCER_FIRE_UPDATE);
- this.cancelDebouncer(DEBOUNCER_STORE);
- this.cancelDebouncer(DEBOUNCER_DRAFT_TOAST);
+ disconnectedCallback() {
+ this.fireUpdateTask?.cancel();
+ this.storeTask?.cancel();
+ this.draftToastTask?.cancel();
if (this.textarea) {
this.textarea.closeDropdown();
}
+ super.disconnectedCallback();
}
_getAuthor(comment: UIComment) {
@@ -495,7 +492,7 @@
_eraseDraftComment() {
// Prevents a race condition in which removing the draft comment occurs
// prior to it being saved.
- this.cancelDebouncer(DEBOUNCER_STORE);
+ this.storeTask?.cancel();
assertIsDefined(this.comment?.path, 'comment.path');
assertIsDefined(this.changeNum, 'changeNum');
@@ -545,7 +542,7 @@
}
_fireUpdate() {
- this.debounce(DEBOUNCER_FIRE_UPDATE, () => {
+ this.fireUpdateTask = debounce(this.fireUpdateTask, () => {
this.dispatchEvent(
new CustomEvent('comment-update', {
detail: this._getEventPayload(),
@@ -587,7 +584,7 @@
this._fireUpdate();
}
if (editing) {
- this.async(() => {
+ setTimeout(() => {
flush();
this.textarea && this.textarea.putCursorAtEnd();
}, 1);
@@ -653,8 +650,8 @@
: this._getPatchNum();
const {path, line, range} = this.comment;
if (path) {
- this.debounce(
- DEBOUNCER_STORE,
+ this.storeTask = debounce(
+ this.storeTask,
() => {
const message = this._messageText;
if (this.changeNum === undefined) {
@@ -736,7 +733,7 @@
}
_fireDiscard() {
- this.cancelDebouncer(DEBOUNCER_FIRE_UPDATE);
+ this.fireUpdateTask?.cancel();
this.dispatchEvent(
new CustomEvent('comment-discard', {
detail: this._getEventPayload(),
@@ -859,7 +856,7 @@
// Cancel the debouncer so that error toasts from the error-manager will
// not be overridden.
- this.cancelDebouncer(DEBOUNCER_DRAFT_TOAST);
+ this.draftToastTask?.cancel();
this._updateRequestToast(
this._numPendingDraftRequests.number,
/* requestFailed=*/ true
@@ -868,8 +865,8 @@
_updateRequestToast(numPending: number, requestFailed?: boolean) {
const message = this._getSavingMessage(numPending, requestFailed);
- this.debounce(
- DEBOUNCER_DRAFT_TOAST,
+ this.draftToastTask = debounce(
+ this.draftToastTask,
() => {
// Note: the event is fired on the body rather than this element because
// this element may not be attached by the time this executes, in which
@@ -930,7 +927,7 @@
_getPatchNum(): PatchSetNum {
const patchNum = this.isOnParent()
- ? ('PARENT' as PatchSetNum)
+ ? ('PARENT' as BasePatchSetNum)
: this.patchNum;
if (patchNum === undefined) throw new Error('patchNum undefined');
return patchNum;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
index 158e8574..aad8c98 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
@@ -485,9 +485,7 @@
on-confirm="_handleConfirmDiscard"
on-cancel="_closeConfirmDiscardOverlay"
>
- <div class="header" slot="header">
- Discard comment
- </div>
+ <div class="header" slot="header">Discard comment</div>
<div class="main" slot="main">
Are you sure you want to discard this draft comment?
</div>
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
index 6c925b0..be647ab 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
@@ -20,7 +20,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
import {__testOnly_UNSAVED_MESSAGE} from './gr-comment.js';
import {SpecialFilePath, Side} from '../../../constants/constants.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {stubRestApi, stubStorage} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-comment');
@@ -115,7 +115,7 @@
});
test('message is not retrieved from storage when other edits', done => {
- const storageStub = sinon.stub(element.storage, 'getDraftComment');
+ const storageStub = stubStorage('getDraftComment');
const loadSpy = sinon.spy(element, '_loadLocalDraft');
element.changeNum = 1;
@@ -135,7 +135,7 @@
});
test('message is retrieved from storage when no other edits', done => {
- const storageStub = sinon.stub(element.storage, 'getDraftComment');
+ const storageStub = stubStorage('getDraftComment');
const loadSpy = sinon.spy(element, '_loadLocalDraft');
element.changeNum = 1;
@@ -442,7 +442,6 @@
setup(() => {
stubRestApi('getAccount').returns(Promise.resolve(null));
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('saveDiffDraft').returns(Promise.resolve({
ok: true,
text() {
@@ -769,7 +768,7 @@
});
MockInteractions.tap(element.shadowRoot
.querySelector('.cancel'));
- element.flushDebouncer('fire-update');
+ element.fireUpdateTask.flush();
element._messageText = '';
flush();
MockInteractions.pressAndReleaseKeyOn(element.textarea, 27); // esc
@@ -868,21 +867,20 @@
test('draft saving/editing', done => {
const dispatchEventStub = sinon.stub(element, 'dispatchEvent');
- const cancelDebounce = sinon.stub(element, 'cancelDebouncer');
element.draft = true;
flush();
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
element._messageText = 'good news, everyone!';
- element.flushDebouncer('fire-update');
- element.flushDebouncer('store');
+ element.fireUpdateTask.flush();
+ element.storeTask.flush();
assert.equal(dispatchEventStub.lastCall.args[0].type, 'comment-update');
assert.isTrue(dispatchEventStub.calledTwice);
element._messageText = 'good news, everyone!';
- element.flushDebouncer('fire-update');
- element.flushDebouncer('store');
+ element.fireUpdateTask.flush();
+ element.storeTask.flush();
assert.isTrue(dispatchEventStub.calledTwice);
MockInteractions.tap(element.shadowRoot
@@ -893,7 +891,7 @@
element._xhrPromise.then(draft => {
assert.equal(dispatchEventStub.lastCall.args[0].type, 'comment-save');
- assert(cancelDebounce.calledWith('store'));
+ assert.isFalse(element.storeTask.isActive());
assert.deepEqual(dispatchEventStub.lastCall.args[0].detail, {
comment: {
@@ -941,8 +939,8 @@
MockInteractions.tap(element.shadowRoot
.querySelector('.edit'));
element._messageText = 'good news, everyone!';
- element.flushDebouncer('fire-update');
- element.flushDebouncer('store');
+ element.fireUpdateTask.flush();
+ element.storeTask.flush();
element.disabled = true;
MockInteractions.tap(element.shadowRoot
@@ -1024,11 +1022,11 @@
test('cancelling an unsaved draft discards, persists in storage', () => {
const discardSpy = sinon.spy(element, '_fireDiscard');
- const storeStub = sinon.stub(element.storage, 'setDraftComment');
- const eraseStub = sinon.stub(element.storage, 'eraseDraftComment');
+ const storeStub = stubStorage('setDraftComment');
+ const eraseStub = stubStorage('eraseDraftComment');
element._messageText = 'test text';
flush();
- element.flushDebouncer('store');
+ element.storeTask.flush();
assert.isTrue(storeStub.called);
assert.equal(storeStub.lastCall.args[1], 'test text');
@@ -1040,10 +1038,10 @@
test('cancelling edit on a saved draft does not store', () => {
element.comment.id = 'foo';
const discardSpy = sinon.spy(element, '_fireDiscard');
- const storeStub = sinon.stub(element.storage, 'setDraftComment');
+ const storeStub = stubStorage('setDraftComment');
element._messageText = 'test text';
flush();
- element.flushDebouncer('store');
+ if (element.storeTask) element.storeTask.flush();
assert.isFalse(storeStub.called);
element._handleCancel({preventDefault: () => {}});
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
index a636a07..0f071abb 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../gr-dialog/gr-dialog';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-confirm-delete-comment-dialog_html';
import {property, customElement} from '@polymer/decorators';
@@ -35,9 +33,7 @@
}
@customElement('gr-confirm-delete-comment-dialog')
-export class GrConfirmDeleteCommentDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrConfirmDeleteCommentDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index 47dacc3..110c242 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -19,8 +19,6 @@
import '../gr-button/gr-button';
import '../gr-icons/gr-icons';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-copy-clipboard_html';
import {GrButton} from '../gr-button/gr-button';
@@ -39,11 +37,8 @@
$: {button: GrButton; icon: IronIconElement; input: HTMLInputElement};
}
-/** @extends PolymerElement */
@customElement('gr-copy-clipboard')
-export class GrCopyClipboard extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrCopyClipboard extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -87,7 +82,7 @@
this.$.input.style.display = 'none';
}
this.$.icon.icon = 'gr-icons:check';
- this.async(
+ setTimeout(
() => (this.$.icon.icon = 'gr-icons:content-copy'),
COPY_TIMEOUT_MS
);
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_html.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_html.ts
index 197c94c..3ccc46f 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
.text {
align-items: center;
display: flex;
@@ -48,6 +48,12 @@
height: 16px;
width: 16px;
}
+ iron-icon {
+ color: var(--deemphasized-text-color);
+ vertical-align: top;
+ --iron-icon-height: 20px;
+ --iron-icon-width: 20px;
+ }
gr-button {
--gr-button: {
padding: 2px;
@@ -59,7 +65,7 @@
class="copyText"
type="text"
bind-value="[[text]]"
- on-tap="_handleInputClick"
+ on-click="_handleInputClick"
readonly=""
>
<input
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
index 119ed20..a5a5433 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.ts
@@ -14,22 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-cursor-manager_html';
+import {BehaviorSubject} from 'rxjs';
import {ScrollMode} from '../../../constants/constants';
-import {customElement, property, observe} from '@polymer/decorators';
-
-export interface GrCursorManager {
- $: {};
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-cursor-manager': GrCursorManager;
- }
-}
/**
* Return type for cursor moves, that indicate whether a move was possible.
@@ -61,33 +47,33 @@
return !(stop instanceof AbortStop);
}
-@customElement('gr-cursor-manager')
-export class GrCursorManager extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
- static get template() {
- return htmlTemplate;
+export class GrCursorManager {
+ get target(): HTMLElement | null {
+ return this.targetSubject.getValue();
}
- @property({type: Object, notify: true})
- target: HTMLElement | null = null;
+ set target(target: HTMLElement | null) {
+ this.targetSubject.next(target);
+ this._scrollToTarget();
+ }
+
+ private targetSubject = new BehaviorSubject<HTMLElement | null>(null);
+
+ target$ = this.targetSubject.asObservable();
/**
* The height of content intended to be included with the target.
*/
- @property({type: Number})
_targetHeight: number | null = null;
/**
* The index of the current target (if any). -1 otherwise.
*/
- @property({type: Number, notify: true})
index = -1;
/**
* The class to apply to the current target. Use null for no class.
*/
- @property({type: String})
cursorTargetClass: string | null = null;
/**
@@ -98,34 +84,33 @@
*
* @type {string|undefined}
*/
- @property({type: String})
scrollMode: string = ScrollMode.NEVER;
/**
* When true, will call element.focus() during scrolling.
*/
- @property({type: Boolean})
focusOnMove = false;
- @property({type: Array})
- stops: Stop[] = [];
+ set stops(stops: Stop[]) {
+ this.stopsInternal = stops;
+ this._updateIndex();
+ }
+
+ get stops(): Stop[] {
+ return this.stopsInternal;
+ }
+
+ private stopsInternal: Stop[] = [];
/** Only non-AbortStop stops. */
get targetableStops(): HTMLElement[] {
return this.stops.filter(isTargetable);
}
- /** @override */
- detached() {
- super.detached();
- this.unsetCursor();
- }
-
/**
* Move the cursor forward. Clipped to the ends of the stop list.
*
- * @param options.filter Will keep going and skip any stops for which this
- * condition is not met.
+ * @param options.filter Skips any stops for which filter returns false.
* @param options.getTargetHeight Optional function to calculate the
* height of the target's 'section'. The height of the target itself is
* sometimes different, used by the diff cursor.
@@ -158,64 +143,86 @@
* The method uses IntersectionObservers API. If browser
* doesn't support this API the method does nothing
*
- * @param condition Optional condition. If a condition
- * is passed only stops which meet conditions are taken into account.
+ * @param filter Skips any stops for which filter returns false.
*/
- moveToVisibleArea(condition?: (el: Element) => boolean) {
- if (!this.stops || !this._isIntersectionObserverSupported()) {
- return;
+ async moveToVisibleArea(filter?: (el: Element) => boolean) {
+ const centerMostStop = await this.getCenterMostStop(filter);
+ // In most cases the target is visible, so scroll is not
+ // needed. But in rare cases the target can become invisible
+ // at this point (due to some scrolling in window).
+ // To avoid jumps set noScroll options.
+ if (centerMostStop) {
+ this.setCursor(centerMostStop, true);
}
- const filteredStops = condition
- ? this.targetableStops.filter(condition)
+ }
+
+ private async getCenterMostStop(
+ filter?: (el: Element) => boolean
+ ): Promise<HTMLElement | undefined> {
+ const visibleEntries = await this.getVisibleEntries(filter);
+ const windowCenter = Math.round(window.innerHeight / 2);
+
+ let centerMostStop: HTMLElement | undefined = undefined;
+ let minDistanceToCenter = Number.MAX_VALUE;
+
+ for (const entry of visibleEntries) {
+ // We are just using the entries here, because entry.boundingClientRect
+ // is already computed, but entry.target.getBoundingClientRect() should
+ // actually yield the same result.
+ const center =
+ entry.boundingClientRect.top +
+ Math.round(entry.boundingClientRect.height / 2);
+ const distanceToWindowCenter = Math.abs(center - windowCenter);
+ if (distanceToWindowCenter < minDistanceToCenter) {
+ // entry.target comes from the filteredStops array,
+ // hence it is an HTMLElement
+ centerMostStop = entry.target as HTMLElement;
+ minDistanceToCenter = distanceToWindowCenter;
+ }
+ }
+ return centerMostStop;
+ }
+
+ private async getVisibleEntries(
+ filter?: (el: Element) => boolean
+ ): Promise<IntersectionObserverEntry[]> {
+ if (!this._isIntersectionObserverSupported()) {
+ throw new Error('Intersection observing not supported');
+ }
+ if (!this.stops) {
+ return [];
+ }
+ const filteredStops = filter
+ ? this.targetableStops.filter(filter)
: this.targetableStops;
- const dims = this._getWindowDims();
- const windowCenter = Math.round(dims.innerHeight / 2);
+ return new Promise(resolve => {
+ let unobservedCount = filteredStops.length;
+ const visibleEntries: IntersectionObserverEntry[] = [];
+ const observer = new IntersectionObserver(entries => {
+ visibleEntries.push(
+ ...entries
+ // In Edge it is recommended to use intersectionRatio instead of
+ // isIntersecting.
+ .filter(
+ entry => entry.isIntersecting || entry.intersectionRatio > 0
+ )
+ );
- let closestToTheCenter: HTMLElement | null = null;
- let minDistanceToCenter: number | null = null;
- let unobservedCount = filteredStops.length;
-
- const observer = new IntersectionObserver(entries => {
- // This callback is called for the first time immediately.
- // Typically it gets all observed stops at once, but
- // sometimes can get them in several chunks.
- entries.forEach(entry => {
- observer.unobserve(entry.target);
-
- // In Edge it is recommended to use intersectionRatio instead of
- // isIntersecting.
- const isInsideViewport =
- entry.isIntersecting || entry.intersectionRatio > 0;
- if (!isInsideViewport) {
- return;
+ // This callback is called for the first time immediately.
+ // Typically it gets all observed stops at once, but
+ // sometimes can get them in several chunks.
+ for (const entry of entries) {
+ observer.unobserve(entry.target);
}
- const center =
- entry.boundingClientRect.top +
- Math.round(entry.boundingClientRect.height / 2);
- const distanceToWindowCenter = Math.abs(center - windowCenter);
- if (
- minDistanceToCenter === null ||
- distanceToWindowCenter < minDistanceToCenter
- ) {
- // entry.target comes from the filteredStops array,
- // hence it is an HTMLElement
- closestToTheCenter = entry.target as HTMLElement;
- minDistanceToCenter = distanceToWindowCenter;
+ unobservedCount -= entries.length;
+ if (unobservedCount === 0) {
+ resolve(visibleEntries);
}
});
- unobservedCount -= entries.length;
- if (unobservedCount === 0 && closestToTheCenter) {
- // set cursor when all stops were observed.
- // In most cases the target is visible, so scroll is not
- // needed. But in rare cases the target can become invisible
- // at this point (due to some scrolling in window).
- // To avoid jumps set noScroll options.
- this.setCursor(closestToTheCenter, true);
+ for (const stop of filteredStops) {
+ observer.observe(stop);
}
});
- filteredStops.forEach(stop => {
- observer.observe(stop);
- });
}
_isIntersectionObserverSupported() {
@@ -386,7 +393,6 @@
}
}
- @observe('stops')
_updateIndex() {
if (!this.target) {
this.index = -1;
@@ -420,26 +426,22 @@
}
_targetIsVisible(top: number) {
- const dims = this._getWindowDims();
return (
this.scrollMode === ScrollMode.KEEP_VISIBLE &&
- top > dims.pageYOffset &&
- top < dims.pageYOffset + dims.innerHeight
+ top > window.pageYOffset &&
+ top < window.pageYOffset + window.innerHeight
);
}
_calculateScrollToValue(top: number, target: HTMLElement) {
- const dims = this._getWindowDims();
- return top + -dims.innerHeight / 3 + target.offsetHeight / 2;
+ return top + -window.innerHeight / 3 + target.offsetHeight / 2;
}
- @observe('target')
_scrollToTarget() {
if (!this.target || this.scrollMode === ScrollMode.NEVER) {
return;
}
- const dims = this._getWindowDims();
const top = this._getTop(this.target);
const bottomIsVisible = this._targetHeight
? this._targetIsVisible(top + this._targetHeight)
@@ -451,7 +453,7 @@
// 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) {
+ if (bottomIsVisible || scrollToValue < window.scrollY) {
return;
}
}
@@ -460,15 +462,6 @@
// instead of half the inner height feels a bit better otherwise the
// element appears to be below the center of the window even when it
// isn't.
- window.scrollTo(dims.scrollX, scrollToValue);
- }
-
- _getWindowDims() {
- return {
- scrollX: window.scrollX,
- scrollY: window.scrollY,
- innerHeight: window.innerHeight,
- pageYOffset: window.pageYOffset,
- };
+ window.scrollTo(window.scrollX, scrollToValue);
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_html.ts b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_html.ts
deleted file mode 100644
index 1489006..0000000
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_html.ts
+++ /dev/null
@@ -1,19 +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';
-
-export const htmlTemplate = html``;
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
index 6f74d6b..01b9a74 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.js
@@ -18,10 +18,9 @@
import '../../../test/common-test-setup-karma.js';
import './gr-cursor-manager.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-import {AbortStop, CursorMoveResult} from './gr-cursor-manager.js';
+import {AbortStop, CursorMoveResult, GrCursorManager} from './gr-cursor-manager.js';
const basicTestFixutre = fixtureFromTemplate(html`
- <gr-cursor-manager cursor-target-class="targeted"></gr-cursor-manager>
<ul>
<li>A</li>
<li>B</li>
@@ -31,180 +30,180 @@
`);
suite('gr-cursor-manager tests', () => {
- let element;
+ let cursor;
let list;
setup(() => {
- const fixtureElements = basicTestFixutre.instantiate();
- element = fixtureElements[0];
- list = fixtureElements[1];
+ list = basicTestFixutre.instantiate();
+ cursor = new GrCursorManager();
+ cursor.cursorTargetClass = 'targeted';
});
test('core cursor functionality', () => {
// The element is initialized into the proper state.
- assert.isArray(element.stops);
- assert.equal(element.stops.length, 0);
- assert.equal(element.index, -1);
- assert.isNotOk(element.target);
+ assert.isArray(cursor.stops);
+ assert.equal(cursor.stops.length, 0);
+ assert.equal(cursor.index, -1);
+ assert.isNotOk(cursor.target);
// Initialize the cursor with its stops.
- element.stops = [...list.querySelectorAll('li')];
+ cursor.stops = [...list.querySelectorAll('li')];
// It should have the stops but it should not be targeting any of them.
- assert.isNotNull(element.stops);
- assert.equal(element.stops.length, 4);
- assert.equal(element.index, -1);
- assert.isNotOk(element.target);
+ assert.isNotNull(cursor.stops);
+ assert.equal(cursor.stops.length, 4);
+ assert.equal(cursor.index, -1);
+ assert.isNotOk(cursor.target);
// Select the third stop.
- element.setCursor(list.children[2]);
+ cursor.setCursor(list.children[2]);
// It should update its internal state and update the element's class.
- assert.equal(element.index, 2);
- assert.equal(element.target, list.children[2]);
+ assert.equal(cursor.index, 2);
+ assert.equal(cursor.target, list.children[2]);
assert.isTrue(list.children[2].classList.contains('targeted'));
- assert.isFalse(element.isAtStart());
- assert.isFalse(element.isAtEnd());
+ assert.isFalse(cursor.isAtStart());
+ assert.isFalse(cursor.isAtEnd());
// Progress the cursor.
- let result = element.next();
+ let result = cursor.next();
// Confirm that the next stop is selected and that the previous stop is
// unselected.
assert.equal(result, CursorMoveResult.MOVED);
- assert.equal(element.index, 3);
- assert.equal(element.target, list.children[3]);
- assert.isTrue(element.isAtEnd());
+ assert.equal(cursor.index, 3);
+ assert.equal(cursor.target, list.children[3]);
+ assert.isTrue(cursor.isAtEnd());
assert.isFalse(list.children[2].classList.contains('targeted'));
assert.isTrue(list.children[3].classList.contains('targeted'));
// Progress the cursor.
- result = element.next();
+ result = cursor.next();
// We should still be at the end.
assert.equal(result, CursorMoveResult.CLIPPED);
- assert.equal(element.index, 3);
- assert.equal(element.target, list.children[3]);
- assert.isTrue(element.isAtEnd());
+ assert.equal(cursor.index, 3);
+ assert.equal(cursor.target, list.children[3]);
+ assert.isTrue(cursor.isAtEnd());
// Wind the cursor all the way back to the first stop.
- result = element.previous();
+ result = cursor.previous();
assert.equal(result, CursorMoveResult.MOVED);
- result = element.previous();
+ result = cursor.previous();
assert.equal(result, CursorMoveResult.MOVED);
- result = element.previous();
+ result = cursor.previous();
assert.equal(result, CursorMoveResult.MOVED);
// The element state should reflect the start of the list.
- assert.equal(element.index, 0);
- assert.equal(element.target, list.children[0]);
- assert.isTrue(element.isAtStart());
+ assert.equal(cursor.index, 0);
+ assert.equal(cursor.target, list.children[0]);
+ assert.isTrue(cursor.isAtStart());
assert.isTrue(list.children[0].classList.contains('targeted'));
const newLi = document.createElement('li');
newLi.textContent = 'Z';
list.insertBefore(newLi, list.children[0]);
- element.stops = [...list.querySelectorAll('li')];
+ cursor.stops = [...list.querySelectorAll('li')];
- assert.equal(element.index, 1);
+ assert.equal(cursor.index, 1);
// De-select all targets.
- element.unsetCursor();
+ cursor.unsetCursor();
// There should now be no cursor target.
assert.isFalse(list.children[1].classList.contains('targeted'));
- assert.isNotOk(element.target);
- assert.equal(element.index, -1);
+ assert.isNotOk(cursor.target);
+ assert.equal(cursor.index, -1);
});
test('isAtStart() returns true when there are no stops', () => {
- element.stops = [];
- assert.isTrue(element.isAtStart());
+ cursor.stops = [];
+ assert.isTrue(cursor.isAtStart());
});
test('isAtEnd() returns true when there are no stops', () => {
- element.stops = [];
- assert.isTrue(element.isAtEnd());
+ cursor.stops = [];
+ assert.isTrue(cursor.isAtEnd());
});
test('next() goes to first element when no cursor is set', () => {
- element.stops = [...list.querySelectorAll('li')];
- const result = element.next();
+ cursor.stops = [...list.querySelectorAll('li')];
+ const result = cursor.next();
assert.equal(result, CursorMoveResult.MOVED);
- assert.equal(element.index, 0);
- assert.equal(element.target, list.children[0]);
+ assert.equal(cursor.index, 0);
+ assert.equal(cursor.target, list.children[0]);
assert.isTrue(list.children[0].classList.contains('targeted'));
- assert.isTrue(element.isAtStart());
- assert.isFalse(element.isAtEnd());
+ assert.isTrue(cursor.isAtStart());
+ assert.isFalse(cursor.isAtEnd());
});
test('next() resets the cursor when there are no stops', () => {
- element.stops = [];
- const result = element.next();
+ cursor.stops = [];
+ const result = cursor.next();
assert.equal(result, CursorMoveResult.NO_STOPS);
- assert.equal(element.index, -1);
- assert.isNotOk(element.target);
+ assert.equal(cursor.index, -1);
+ assert.isNotOk(cursor.target);
assert.isFalse(list.children[1].classList.contains('targeted'));
});
test('previous() goes to last element when no cursor is set', () => {
- element.stops = [...list.querySelectorAll('li')];
- const result = element.previous();
+ cursor.stops = [...list.querySelectorAll('li')];
+ const result = cursor.previous();
assert.equal(result, CursorMoveResult.MOVED);
const lastIndex = list.children.length - 1;
- assert.equal(element.index, lastIndex);
- assert.equal(element.target, list.children[lastIndex]);
+ assert.equal(cursor.index, lastIndex);
+ assert.equal(cursor.target, list.children[lastIndex]);
assert.isTrue(list.children[lastIndex].classList.contains('targeted'));
- assert.isFalse(element.isAtStart());
- assert.isTrue(element.isAtEnd());
+ assert.isFalse(cursor.isAtStart());
+ assert.isTrue(cursor.isAtEnd());
});
test('previous() resets the cursor when there are no stops', () => {
- element.stops = [];
- const result = element.previous();
+ cursor.stops = [];
+ const result = cursor.previous();
assert.equal(result, CursorMoveResult.NO_STOPS);
- assert.equal(element.index, -1);
- assert.isNotOk(element.target);
+ assert.equal(cursor.index, -1);
+ assert.isNotOk(cursor.target);
assert.isFalse(list.children[1].classList.contains('targeted'));
});
test('_moveCursor', () => {
// Initialize the cursor with its stops.
- element.stops = [...list.querySelectorAll('li')];
+ cursor.stops = [...list.querySelectorAll('li')];
// Select the first stop.
- element.setCursor(list.children[0]);
+ cursor.setCursor(list.children[0]);
const getTargetHeight = sinon.stub();
// Move the cursor without an optional get target height function.
- element._moveCursor(1);
+ cursor._moveCursor(1);
assert.isFalse(getTargetHeight.called);
// Move the cursor with an optional get target height function.
- element._moveCursor(1, {getTargetHeight});
+ cursor._moveCursor(1, {getTargetHeight});
assert.isTrue(getTargetHeight.called);
});
test('_moveCursor from for invalid index does not check height', () => {
- element.stops = [];
+ cursor.stops = [];
const getTargetHeight = sinon.stub();
- element._moveCursor(1, () => false, {getTargetHeight});
+ cursor._moveCursor(1, () => false, {getTargetHeight});
assert.isFalse(getTargetHeight.called);
});
test('setCursorAtIndex with noScroll', () => {
- sinon.stub(element, '_targetIsVisible').callsFake(() => false);
+ sinon.stub(cursor, '_targetIsVisible').callsFake(() => false);
const scrollStub = sinon.stub(window, 'scrollTo');
- element.stops = [...list.querySelectorAll('li')];
- element.scrollMode = 'keep-visible';
+ cursor.stops = [...list.querySelectorAll('li')];
+ cursor.scrollMode = 'keep-visible';
- element.setCursorAtIndex(1, true);
+ cursor.setCursorAtIndex(1, true);
assert.isFalse(scrollStub.called);
- element.setCursorAtIndex(2);
+ cursor.setCursorAtIndex(2);
assert.isTrue(scrollStub.called);
});
@@ -212,30 +211,30 @@
const isLetterB = function(row) {
return row.textContent === 'B';
};
- element.stops = [...list.querySelectorAll('li')];
+ cursor.stops = [...list.querySelectorAll('li')];
// Start cursor at the first stop.
- element.setCursor(list.children[0]);
+ cursor.setCursor(list.children[0]);
// Move forward to meet the next condition.
- element.next({filter: isLetterB});
- assert.equal(element.index, 1);
+ cursor.next({filter: isLetterB});
+ assert.equal(cursor.index, 1);
// Nothing else meets the condition, should be at last stop.
- element.next({filter: isLetterB});
- assert.equal(element.index, 3);
+ cursor.next({filter: isLetterB});
+ assert.equal(cursor.index, 3);
// Should stay at last stop if try to proceed.
- element.next({filter: isLetterB});
- assert.equal(element.index, 3);
+ cursor.next({filter: isLetterB});
+ assert.equal(cursor.index, 3);
// Go back to the previous condition met. Should be back at.
// stop 1.
- element.previous({filter: isLetterB});
- assert.equal(element.index, 1);
+ cursor.previous({filter: isLetterB});
+ assert.equal(cursor.index, 1);
// Go back. No more meet the condition. Should be at stop 0.
- element.previous({filter: isLetterB});
- assert.equal(element.index, 0);
+ cursor.previous({filter: isLetterB});
+ assert.equal(cursor.index, 0);
});
test('focusOnMove prop', () => {
@@ -243,129 +242,123 @@
for (let i = 0; i < listEls.length; i++) {
sinon.spy(listEls[i], 'focus');
}
- element.stops = listEls;
- element.setCursor(list.children[0]);
+ cursor.stops = listEls;
+ cursor.setCursor(list.children[0]);
- element.focusOnMove = false;
- element.next();
- assert.isFalse(element.target.focus.called);
+ cursor.focusOnMove = false;
+ cursor.next();
+ assert.isFalse(cursor.target.focus.called);
- element.focusOnMove = true;
- element.next();
- assert.isTrue(element.target.focus.called);
+ cursor.focusOnMove = true;
+ cursor.next();
+ assert.isTrue(cursor.target.focus.called);
});
suite('_scrollToTarget', () => {
let scrollStub;
setup(() => {
- element.stops = [...list.querySelectorAll('li')];
- element.scrollMode = 'keep-visible';
+ cursor.stops = [...list.querySelectorAll('li')];
+ cursor.scrollMode = 'keep-visible';
// There is a target which has a targetNext
- element.setCursor(list.children[0]);
- element._moveCursor(1);
+ cursor.setCursor(list.children[0]);
+ cursor._moveCursor(1);
scrollStub = sinon.stub(window, 'scrollTo');
window.innerHeight = 60;
});
test('Called when top and bottom not visible', () => {
- sinon.stub(element, '_targetIsVisible').returns(false);
- element._scrollToTarget();
+ sinon.stub(cursor, '_targetIsVisible').returns(false);
+ cursor._scrollToTarget();
assert.isTrue(scrollStub.called);
});
test('Not called when top and bottom visible', () => {
- sinon.stub(element, '_targetIsVisible').returns(true);
- element._scrollToTarget();
+ sinon.stub(cursor, '_targetIsVisible').returns(true);
+ cursor._scrollToTarget();
assert.isFalse(scrollStub.called);
});
test('Called when top is visible, bottom is not, scroll is lower', () => {
- const visibleStub = sinon.stub(element, '_targetIsVisible').callsFake(
+ const visibleStub = sinon.stub(cursor, '_targetIsVisible').callsFake(
() => visibleStub.callCount === 2);
- sinon.stub(element, '_getWindowDims').returns({
- scrollX: 123,
- scrollY: 15,
- innerHeight: 1000,
- pageYOffset: 0,
- });
- sinon.stub(element, '_calculateScrollToValue').returns(20);
- element._scrollToTarget();
+ window.scrollX = 123;
+ window.scrollY = 15;
+ window.innerHeight = 1000;
+ window.pageYOffset = 0;
+ sinon.stub(cursor, '_calculateScrollToValue').returns(20);
+ cursor._scrollToTarget();
assert.isTrue(scrollStub.called);
assert.isTrue(scrollStub.calledWithExactly(123, 20));
assert.equal(visibleStub.callCount, 2);
});
test('Called when top is visible, bottom not, scroll is higher', () => {
- const visibleStub = sinon.stub(element, '_targetIsVisible').callsFake(
+ const visibleStub = sinon.stub(cursor, '_targetIsVisible').callsFake(
() => visibleStub.callCount === 2);
- sinon.stub(element, '_getWindowDims').returns({
- scrollX: 123,
- scrollY: 25,
- innerHeight: 1000,
- pageYOffset: 0,
- });
- sinon.stub(element, '_calculateScrollToValue').returns(20);
- element._scrollToTarget();
+ window.scrollX = 123;
+ window.scrollY = 25;
+ window.innerHeight = 1000;
+ window.pageYOffset = 0;
+ sinon.stub(cursor, '_calculateScrollToValue').returns(20);
+ cursor._scrollToTarget();
assert.isFalse(scrollStub.called);
assert.equal(visibleStub.callCount, 2);
});
test('_calculateScrollToValue', () => {
- sinon.stub(element, '_getWindowDims').returns({
- scrollX: 123,
- scrollY: 25,
- innerHeight: 300,
- pageYOffset: 0,
- });
- assert.equal(element._calculateScrollToValue(1000, {offsetHeight: 10}),
+ window.scrollX = 123;
+ window.scrollY = 25;
+ window.innerHeight = 300;
+ window.pageYOffset = 0;
+ assert.equal(cursor._calculateScrollToValue(1000, {offsetHeight: 10}),
905);
});
});
suite('AbortStops', () => {
test('next() does not skip AbortStops', () => {
- element.stops = [
+ cursor.stops = [
document.createElement('li'),
new AbortStop(),
document.createElement('li'),
];
- element.setCursorAtIndex(0);
+ cursor.setCursorAtIndex(0);
- const result = element.next();
+ const result = cursor.next();
assert.equal(result, CursorMoveResult.ABORTED);
- assert.equal(element.index, 0);
+ assert.equal(cursor.index, 0);
});
test('setCursorAtIndex() does not target AbortStops', () => {
- element.stops = [
+ cursor.stops = [
document.createElement('li'),
new AbortStop(),
document.createElement('li'),
];
- element.setCursorAtIndex(1);
- assert.equal(element.index, -1);
+ cursor.setCursorAtIndex(1);
+ assert.equal(cursor.index, -1);
});
test('moveToStart() does not target AbortStop', () => {
- element.stops = [
+ cursor.stops = [
new AbortStop(),
document.createElement('li'),
document.createElement('li'),
];
- element.moveToStart();
- assert.equal(element.index, -1);
+ cursor.moveToStart();
+ assert.equal(cursor.index, -1);
});
test('moveToEnd() does not target AbortStop', () => {
- element.stops = [
+ cursor.stops = [
document.createElement('li'),
document.createElement('li'),
new AbortStop(),
];
- element.moveToEnd();
- assert.equal(element.index, -1);
+ cursor.moveToEnd();
+ assert.equal(cursor.index, -1);
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
index 5bb4f4c..489b489 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-date-formatter_html';
import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
@@ -78,9 +76,7 @@
}
@customElement('gr-date-formatter')
-export class GrDateFormatter extends TooltipMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrDateFormatter extends TooltipMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -134,8 +130,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._loadPreferences();
}
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
index 97bbf68..4808832 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
color: inherit;
display: inline;
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index fa6403a..7022a39 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -16,8 +16,6 @@
*/
import '../gr-button/gr-button';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dialog_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -36,9 +34,7 @@
}
@customElement('gr-dialog')
-export class GrDialog extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.js b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
similarity index 74%
rename from polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.js
rename to polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
index 1238168..e7b7130 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_test.ts
@@ -15,14 +15,15 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-dialog.js';
-import {isHidden} from '../../../test/test-utils.js';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import '../../../test/common-test-setup-karma';
+import {GrDialog} from './gr-dialog';
+import {isHidden, queryAndAssert} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-dialog');
suite('gr-dialog tests', () => {
- let element;
+ let element: GrDialog;
setup(() => {
element = basicFixture.instantiate();
@@ -34,12 +35,10 @@
element.addEventListener('confirm', confirm);
element.addEventListener('cancel', cancel);
- MockInteractions.tap(
- element.shadowRoot.querySelector('gr-button[primary]'));
+ MockInteractions.tap(queryAndAssert(element, 'gr-button[primary]'));
assert.equal(confirm.callCount, 1);
- MockInteractions.tap(
- element.shadowRoot.querySelector('gr-button:not([primary])'));
+ MockInteractions.tap(queryAndAssert(element, 'gr-button:not([primary])'));
assert.equal(cancel.callCount, 1);
});
@@ -48,7 +47,11 @@
const handleConfirmStub = sinon.stub(element, '_handleConfirm');
const handleKeydownSpy = sinon.spy(element, '_handleKeydown');
MockInteractions.pressAndReleaseKeyOn(
- element.shadowRoot.querySelector('main'), 13, null, 'enter');
+ queryAndAssert(element, 'main'),
+ 13,
+ null,
+ 'enter'
+ );
flush();
assert.isTrue(handleKeydownSpy.called);
@@ -56,7 +59,11 @@
element.confirmOnEnter = true;
MockInteractions.pressAndReleaseKeyOn(
- element.shadowRoot.querySelector('main'), 13, null, 'enter');
+ queryAndAssert(element, 'main'),
+ 13,
+ null,
+ 'enter'
+ );
flush();
assert.isTrue(handleConfirmStub.called);
@@ -81,11 +88,11 @@
});
test('empty cancel label hides cancel btn', () => {
- assert.isFalse(isHidden(element.$.cancel));
+ const cancelButton = queryAndAssert(element, '#cancel');
+ assert.isFalse(isHidden(cancelButton));
element.cancelLabel = '';
flush();
- assert.isTrue(isHidden(element.$.cancel));
+ assert.isTrue(isHidden(cancelButton));
});
});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
index 5810222..70a7bf3 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
@@ -18,8 +18,6 @@
import '../../../styles/shared-styles';
import '../gr-button/gr-button';
import '../gr-select/gr-select';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-diff-preferences_html';
import {customElement, property} from '@polymer/decorators';
@@ -40,9 +38,7 @@
}
@customElement('gr-diff-preferences')
-export class GrDiffPreferences extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDiffPreferences extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
index 246d192..ed3d695 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
@@ -189,9 +189,9 @@
>
<option value="IGNORE_NONE">None</option>
<option value="IGNORE_TRAILING">Trailing</option>
- <option value="IGNORE_LEADING_AND_TRAILING"
- >Leading & trailing</option
- >
+ <option value="IGNORE_LEADING_AND_TRAILING">
+ Leading & trailing
+ </option>
<option value="IGNORE_ALL">All</option>
</select>
</gr-select>
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
index 4c2a417..19cbb22 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
@@ -17,8 +17,6 @@
import '@polymer/paper-tabs/paper-tabs';
import '../gr-shell-command/gr-shell-command';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-download-commands_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -43,9 +41,7 @@
}
@customElement('gr-download-commands')
-export class GrDownloadCommands extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDownloadCommands extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -66,8 +62,8 @@
private readonly restApiService = appContext.restApiService;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this._getLoggedIn().then(loggedIn => {
this._loggedIn = loggedIn;
});
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
index 888f34f..ef46cec 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
@@ -22,8 +22,6 @@
import '../gr-date-formatter/gr-date-formatter';
import '../gr-select/gr-select';
import '../gr-file-status-chip/gr-file-status-chip';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dropdown-list_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -64,9 +62,7 @@
export type DropDownValueChangeEvent = CustomEvent<ValueChangeDetail>;
@customElement('gr-dropdown-list')
-export class GrDropdownList extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrDropdownList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -103,7 +99,7 @@
_handleDropdownClick() {
// async is needed so that that the click event is fired before the
// dropdown closes (This was a bug for touch devices).
- this.async(() => {
+ setTimeout(() => {
this.$.dropdown.close();
}, 1);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.js b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.js
index c2c8d68..909a3bbf 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.js
@@ -17,7 +17,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-dropdown-list.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-dropdown-list');
@@ -25,7 +24,6 @@
let element;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index ae9bfd7..a4a6fe3 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -20,8 +20,6 @@
import '../gr-tooltip-content/gr-tooltip-content';
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dropdown_html';
import {getBaseUrl} from '../../../utils/url-util';
@@ -42,7 +40,6 @@
export interface GrDropdown {
$: {
dropdown: IronDropdownElement;
- cursor: GrCursorManager;
};
}
@@ -66,9 +63,7 @@
}
@customElement('gr-dropdown')
-export class GrDropdown extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrDropdown extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -107,6 +102,10 @@
@property({type: Number})
verticalOffset = 40;
+ /** Propagates/Reflects the `opened` property of the <iron-dropdown> */
+ @property({type: Boolean, notify: true})
+ opened = false;
+
/**
* List the IDs of dropdown buttons to be disabled. (Note this only
* disables buttons and not link entries.)
@@ -114,12 +113,6 @@
@property({type: Array})
disabledIds: string[] = [];
- /**
- * The elements of the list.
- */
- @property({type: Array})
- _listElements: Element[] = [];
-
get keyBindings() {
return {
down: '_handleDown',
@@ -129,6 +122,20 @@
};
}
+ private cursor = new GrCursorManager();
+
+ constructor() {
+ super();
+ this.cursor.cursorTargetClass = 'selected';
+ this.cursor.focusOnMove = true;
+ }
+
+ /** @override */
+ disconnectedCallback() {
+ this.cursor.unsetCursor();
+ super.disconnectedCallback();
+ }
+
/**
* Handle the up key.
*/
@@ -136,7 +143,7 @@
if (this.$.dropdown.opened) {
e.preventDefault();
e.stopPropagation();
- this.$.cursor.previous();
+ this.cursor.previous();
} else {
this._open();
}
@@ -149,7 +156,7 @@
if (this.$.dropdown.opened) {
e.preventDefault();
e.stopPropagation();
- this.$.cursor.next();
+ this.cursor.next();
} else {
this._open();
}
@@ -176,8 +183,8 @@
// TODO(milutin): This solution is not particularly robust in general.
// Since gr-tooltip-content click on shadow dom is not propagated down,
// we have to target `a` inside it.
- if (this.$.cursor.target !== null) {
- const el = this.$.cursor.target.querySelector(':not([hidden]) a');
+ if (this.cursor.target !== null) {
+ const el = this.cursor.target.querySelector(':not([hidden]) a');
if (el) {
(el as HTMLElement).click();
}
@@ -194,6 +201,10 @@
this._close();
}
+ handleOpenedChanged(e: CustomEvent) {
+ this.opened = e.detail.value;
+ }
+
/**
* Handle a click on the button to open the dropdown.
*/
@@ -213,14 +224,14 @@
_open() {
this.$.dropdown.open();
this._resetCursorStops();
- this.$.cursor.setCursorAtIndex(0);
- if (this.$.cursor.target !== null) this.$.cursor.target.focus();
+ this.cursor.setCursorAtIndex(0);
+ if (this.cursor.target !== null) this.cursor.target.focus();
}
_close() {
// async is needed so that that the click event is fired before the
// dropdown closes (This was a bug for touch devices).
- this.async(() => {
+ setTimeout(() => {
this.$.dropdown.close();
}, 1);
}
@@ -329,7 +340,7 @@
_resetCursorStops() {
if (this.items && this.items.length > 0 && this.$.dropdown.opened) {
flush();
- this._listElements =
+ this.cursor.stops =
this.root !== null ? Array.from(this.root.querySelectorAll('li')) : [];
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
index c767edd..e754c9c 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
@@ -28,8 +28,11 @@
.dropdown-content {
background-color: var(--dropdown-background-color);
box-shadow: var(--elevation-level-2);
+ min-width: 112px;
+ max-width: 280px;
}
gr-button {
+ vertical-align: top;
@apply --gr-button;
}
gr-avatar {
@@ -103,6 +106,7 @@
allow-outside-scroll="true"
horizontal-align="[[horizontalAlign]]"
on-click="_handleDropdownClick"
+ on-opened-changed="handleOpenedChanged"
>
<div class="dropdown-content" slot="dropdown-content">
<ul>
@@ -158,11 +162,4 @@
</ul>
</div>
</iron-dropdown>
- <gr-cursor-manager
- id="cursor"
- cursor-target-class="selected"
- scroll-mode="never"
- focus-on-move=""
- stops="[[_listElements]]"
- ></gr-cursor-manager>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.js
index 02bffe4..c271b41 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.js
@@ -18,7 +18,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-dropdown.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-dropdown');
@@ -26,7 +25,6 @@
let element;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
element = basicFixture.instantiate();
});
@@ -155,7 +153,7 @@
});
test('down', () => {
- const stub = sinon.stub(element.$.cursor, 'next');
+ const stub = sinon.stub(element.cursor, 'next');
assert.isFalse(element.$.dropdown.opened);
MockInteractions.pressAndReleaseKeyOn(element, 40);
assert.isTrue(element.$.dropdown.opened);
@@ -164,7 +162,7 @@
});
test('up', () => {
- const stub = sinon.stub(element.$.cursor, 'previous');
+ const stub = sinon.stub(element.cursor, 'previous');
assert.isFalse(element.$.dropdown.opened);
MockInteractions.pressAndReleaseKeyOn(element, 38);
assert.isTrue(element.$.dropdown.opened);
@@ -179,7 +177,7 @@
MockInteractions.pressAndReleaseKeyOn(element, 32); // Space
assert.isTrue(element.$.dropdown.opened);
- const el = element.$.cursor.target.querySelector(':not([hidden]) a');
+ const el = element.cursor.target.querySelector(':not([hidden]) a');
const stub = sinon.stub(el, 'click');
MockInteractions.pressAndReleaseKeyOn(element, 32); // Space
assert.isTrue(stub.called);
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
index 2780fbe..096697f 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.ts
@@ -16,17 +16,14 @@
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
import '../../../styles/shared-styles';
-import '../gr-storage/gr-storage';
import '../gr-button/gr-button';
-import {GrStorage} from '../gr-storage/gr-storage';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
import {htmlTemplate} from './gr-editable-content_html';
import {fireAlert, fireEvent} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {KnownExperimentId} from '../../../services/flags/flags';
+import {debounce, DelayedTask} from '../../../utils/async-util';
const RESTORED_MESSAGE = 'Content restored from a previous edit.';
const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
@@ -37,12 +34,8 @@
}
}
-const DEBOUNCER_STORE = 'store';
-
@customElement('gr-editable-content')
-export class GrEditableContent extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrEditableContent extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -116,12 +109,14 @@
@property({type: Boolean})
_isNewChangeSummaryUiEnabled = false;
- private readonly storage = new GrStorage();
+ private readonly storage = appContext.storageService;
private readonly flagsService = appContext.flagsService;
private readonly reporting = appContext.reportingService;
+ private storeTask?: DelayedTask;
+
/** @override */
ready() {
super.ready();
@@ -131,8 +126,9 @@
}
/** @override */
- detached() {
- this.cancelDebouncer(DEBOUNCER_STORE);
+ disconnectedCallback() {
+ this.storeTask?.cancel();
+ super.disconnectedCallback();
}
_contentChanged() {
@@ -151,8 +147,8 @@
if (!this.storageKey) return;
const storageKey = this.storageKey;
- this.debounce(
- DEBOUNCER_STORE,
+ this.storeTask = debounce(
+ this.storeTask,
() => {
if (newContent.length) {
this.storage.setEditableContentItem(storageKey, newContent);
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
index 0f530bf..68b8121 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
@@ -62,7 +62,6 @@
background-color: var(--view-background-color);
display: flex;
justify-content: flex-end;
- margin-bottom: 8px;
border-top-width: 1px;
border-top-style: solid;
border-radius: 0 0 4px 4px;
@@ -88,6 +87,11 @@
.save-button {
margin-right: var(--spacing-xs);
}
+ gr-button {
+ font-family: var(--font-family);
+ line-height: var(--line-height-normal);
+ padding: var(--spacing-xs);
+ }
</style>
<div
class$="viewer new-change-summary-[[_isNewChangeSummaryUiEnabled]]"
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js
index b99b119..7977f4d 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.js
@@ -126,7 +126,7 @@
element._newContent = 'new content';
flush();
- element.flushDebouncer('store');
+ element.storeTask.flush();
assert.isTrue(storeStub.called);
assert.deepEqual(
@@ -135,7 +135,7 @@
element._newContent = '';
flush();
- element.flushDebouncer('store');
+ element.storeTask.flush();
assert.isTrue(eraseStub.called);
assert.deepEqual([element.storageKey], eraseStub.lastCall.args);
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index 6f0e84a..c758455 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -18,8 +18,7 @@
import '@polymer/paper-input/paper-input';
import '../../../styles/shared-styles';
import '../gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import '../../shared/gr-autocomplete/gr-autocomplete';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {customElement, property} from '@polymer/decorators';
@@ -28,6 +27,10 @@
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PaperInputElementExt} from '../../../types/types';
import {CustomKeyboardEvent} from '../../../types/events';
+import {
+ AutocompleteQuery,
+ GrAutocomplete,
+} from '../gr-autocomplete/gr-autocomplete';
const AWAIT_MAX_ITERS = 10;
const AWAIT_STEP = 5;
@@ -40,15 +43,12 @@
export interface GrEditableLabel {
$: {
- input: PaperInputElementExt;
dropdown: IronDropdownElement;
};
}
@customElement('gr-editable-label')
-export class GrEditableLabel extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrEditableLabel extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -92,6 +92,12 @@
@property({type: Boolean})
showAsEditPencil = false;
+ @property({type: Boolean})
+ autocomplete = false;
+
+ @property({type: Object})
+ query?: AutocompleteQuery;
+
/** @override */
ready() {
super.ready();
@@ -120,8 +126,9 @@
if (this.readOnly || this.editing) return;
return this._open().then(() => {
this._nativeInput.focus();
- if (!this.$.input.value) return;
- this._nativeInput.setSelectionRange(0, this.$.input.value.length);
+ const input = this.getInput();
+ if (!input?.value) return;
+ this._nativeInput.setSelectionRange(0, input.value.length);
});
}
@@ -133,7 +140,7 @@
_open() {
this.$.dropdown.open();
- this._inputText = this.value;
+ this._inputText = this.value || '';
this.editing = true;
return new Promise<void>(resolve => {
@@ -148,7 +155,7 @@
_awaitOpen(fn: () => void) {
let iters = 0;
const step = () => {
- this.async(() => {
+ setTimeout(() => {
if (this.$.dropdown.style.display !== 'none') {
fn.call(this);
} else if (iters++ < AWAIT_MAX_ITERS) {
@@ -190,8 +197,9 @@
get _nativeInput(): HTMLInputElement {
// In Polymer 2 inputElement isn't nativeInput anymore
- return (this.$.input.$.nativeInput ||
- this.$.input.inputElement) as HTMLInputElement;
+ return (this.getInput()?.$.nativeInput ||
+ this.getInput()?.inputElement ||
+ this.getGrAutocomplete()) as HTMLInputElement;
}
_handleEnter(e: CustomKeyboardEvent) {
@@ -212,6 +220,10 @@
}
}
+ _handleCommit() {
+ this._save();
+ }
+
_computeLabelClass(readOnly?: boolean, value?: string, placeholder?: string) {
const classes = [];
if (!readOnly) {
@@ -226,4 +238,12 @@
_updateTitle(value?: string) {
this.setAttribute('title', this._computeLabel(value, this.placeholder));
}
+
+ getInput(): PaperInputElementExt | null {
+ return this.shadowRoot!.querySelector<PaperInputElementExt>('#input');
+ }
+
+ getGrAutocomplete(): GrAutocomplete | null {
+ return this.shadowRoot!.querySelector<GrAutocomplete>('#autocomplete');
+ }
}
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
index ad4fead..a227482 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_html.ts
@@ -73,8 +73,8 @@
--iron-icon-height: 18px;
--iron-icon-width: 18px;
}
- gr-button.new-change-summary-true {
- --padding: 1px 4px;
+ gr-button.pencil {
+ --padding: 0px 0px;
}
</style>
<template is="dom-if" if="[[!showAsEditPencil]]">
@@ -89,7 +89,7 @@
<template is="dom-if" if="[[showAsEditPencil]]">
<gr-button
link=""
- class$="new-change-summary-true [[_computeLabelClass(readOnly, value, placeholder)]]"
+ class$="pencil [[_computeLabelClass(readOnly, value, placeholder)]]"
on-click="_showDropdown"
title="[[_computeLabel(value, placeholder)]]"
><iron-icon icon="gr-icons:edit"></iron-icon
@@ -105,12 +105,24 @@
>
<div class="dropdown-content" slot="dropdown-content">
<div class="inputContainer">
- <paper-input
- id="input"
- label="[[labelText]]"
- maxlength="[[maxLength]]"
- value="{{_inputText}}"
- ></paper-input>
+ <template is="dom-if" if="[[!autocomplete]]">
+ <paper-input
+ id="input"
+ label="[[labelText]]"
+ maxlength="[[maxLength]]"
+ value="{{_inputText}}"
+ ></paper-input>
+ </template>
+ <template is="dom-if" if="[[autocomplete]]">
+ <gr-autocomplete
+ label="[[labelText]]"
+ id="autocomplete"
+ text="{{_inputText}}"
+ query="[[query]]"
+ on-commit="_handleCommit"
+ >
+ </gr-autocomplete>
+ </template>
<div class="buttons">
<gr-button link="" id="cancelBtn" on-click="_cancel"
>cancel</gr-button
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
index 2bdc570..3e217f0 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.js
@@ -50,7 +50,8 @@
await flush();
// In Polymer 2 inputElement isn't nativeInput anymore
- input = element.$.input.$.nativeInput || element.$.input.inputElement;
+ const paperInput = element.shadowRoot.querySelector('#input');
+ input = paperInput.$.nativeInput || paperInput.inputElement;
});
test('element render', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
index 9298fa3..cfa67fd 100644
--- a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {htmlTemplate} from './gr-file-status-chip_html';
import {customElement, property} from '@polymer/decorators';
import {PolymerElement} from '@polymer/polymer/polymer-element';
@@ -35,9 +33,7 @@
};
@customElement('gr-file-status-chip')
-export class GrFileStatusChip extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrFileStatusChip extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip_html.ts b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip_html.ts
index 9e49868..6c7f3e0a 100644
--- a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip_html.ts
@@ -25,7 +25,7 @@
padding: 0 var(--spacing-m);
color: var(--primary-text-color);
font-size: var(--font-size-small);
- background-color: var(--dark-add-highlight-color);
+ background-color: var(--file-status-added);
}
.status.invisible,
.status.M {
@@ -34,10 +34,10 @@
.status.D,
.status.R,
.status.W {
- background-color: var(--dark-remove-highlight-color);
+ background-color: var(--file-status-changed);
}
.status.U {
- background-color: var(--comment-background-color);
+ background-color: var(--file-status-unchanged);
}
</style>
<span
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index a6c7b92..17b659f 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -16,8 +16,6 @@
*/
import '../gr-linked-text/gr-linked-text';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
import {htmlTemplate} from './gr-formatted-text_html';
@@ -45,9 +43,7 @@
}
@customElement('gr-formatted-text')
-export class GrFormattedText extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrFormattedText extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_html.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_html.ts
index 1688a0d..04e4954 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_html.ts
@@ -17,7 +17,7 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="shared-styles">
+ <style>
:host {
display: block;
font-family: var(--font-family);
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index ddae8ea..abd4469 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -20,8 +20,6 @@
import '../gr-avatar/gr-avatar';
import '../gr-button/gr-button';
import {hovercardBehaviorMixin} from '../gr-hovercard/gr-hovercard-behavior';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard-account_html';
import {appContext} from '../../../services/app-context';
@@ -48,9 +46,7 @@
import {assertIsDefined} from '../../../utils/common-util';
@customElement('gr-hovercard-account')
-export class GrHovercardAccount extends GestureEventListeners(
- hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
-) {
+export class GrHovercardAccount extends hovercardBehaviorMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -96,8 +92,8 @@
this.reporting = appContext.reportingService;
}
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
this.restApiService.getConfig().then(config => {
this._config = config;
});
@@ -139,9 +135,7 @@
_getReviewerState(account: AccountInfo, change: ChangeInfo) {
if (
change.reviewers[ReviewerState.REVIEWER]?.some(
- (reviewer: AccountInfo) => {
- return reviewer._account_id === account._account_id;
- }
+ (reviewer: AccountInfo) => reviewer._account_id === account._account_id
)
) {
return ReviewerState.REVIEWER;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
index b8f0161..48de78e 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
@@ -16,19 +16,17 @@
*/
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {Debouncer} from '@polymer/polymer/lib/utils/debounce';
-import {timeOut} from '@polymer/polymer/lib/utils/async';
import {getRootElement} from '../../../scripts/rootElement';
import {Constructor} from '../../../utils/common-util';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
import {property, observe} from '@polymer/decorators';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {
pushScrollLock,
removeScrollLock,
} from '@polymer/iron-overlay-behavior/iron-scroll-manager';
import {ShowAlertEventDetail} from '../../../types/events';
+import {debounce, DelayedTask} from '../../../utils/async-util';
interface ReloadEventDetail {
clearPatchset?: boolean;
}
@@ -37,6 +35,26 @@
const HIDE_CLASS = 'hide';
/**
+ * ID for the container element.
+ */
+const containerId = 'gr-hovercard-container';
+
+export function getHovercardContainer(
+ options: {createIfNotExists: boolean} = {createIfNotExists: false}
+): HTMLElement | null {
+ let container = getRootElement().querySelector<HTMLElement>(
+ `#${containerId}`
+ );
+ if (!container && options.createIfNotExists) {
+ // If it does not exist, create and initialize the hovercard container.
+ container = document.createElement('div');
+ container.setAttribute('id', containerId);
+ getRootElement().appendChild(container);
+ }
+ return container;
+}
+
+/**
* How long should we wait before showing the hovercard when the user hovers
* over the element?
*/
@@ -55,11 +73,8 @@
*
* @example
*
- * // LegacyElementMixin is still needed to support the old lifecycles
- * // TODO: Replace old life cycles with new ones.
- *
* class YourComponent extends hovercardBehaviorMixin(
- * LegacyElementMixin(PolymerElement)
+ * PolymerElement
*
* @see gr-hovercard.ts
*
@@ -68,7 +83,7 @@
* @mixinFunction
*/
export const hovercardBehaviorMixin = dedupingMixin(
- <T extends Constructor<PolymerElement & LegacyElementMixin>>(
+ <T extends Constructor<PolymerElement>>(
superClass: T
): T & Constructor<GrHovercardBehaviorInterface> => {
/**
@@ -77,7 +92,7 @@
*/
class Mixin extends superClass {
@property({type: Object})
- _target: Element | null = null;
+ _target: HTMLElement | null = null;
// Determines whether or not the hovercard is visible.
@property({type: Boolean})
@@ -104,93 +119,78 @@
@property({type: Object})
container: HTMLElement | null = null;
- /**
- * ID for the container element.
- */
- @property({type: String})
- containerId = 'gr-hovercard-container';
+ private hideTask?: DelayedTask;
- private hideDebouncer: Debouncer | null = null;
-
- private showDebouncer: Debouncer | null = null;
+ private showTask?: DelayedTask;
private isScheduledToShow?: boolean;
private isScheduledToHide?: boolean;
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
if (!this._target) {
this._target = this.target;
}
- this.listen(this._target, 'mouseenter', 'debounceShow');
- this.listen(this._target, 'focus', 'debounceShow');
- this.listen(this._target, 'mouseleave', 'debounceHide');
- this.listen(this._target, 'blur', 'debounceHide');
+ this._target.addEventListener('mouseenter', this.debounceShow);
+ this._target.addEventListener('focus', this.debounceShow);
+ this._target.addEventListener('mouseleave', this.debounceHide);
+ this._target.addEventListener('blur', this.debounceHide);
// when click, dismiss immediately
- this.listen(this._target, 'click', 'hide');
+ this._target.addEventListener('click', this.hide);
// show the hovercard if mouse moves to hovercard
// this will cancel pending hide as well
- this.listen(this, 'mouseenter', 'show');
- this.listen(this, 'mouseenter', 'lock');
+ this.addEventListener('mouseenter', this.show);
+ this.addEventListener('mouseenter', this.lock);
// when leave hovercard, hide it immediately
- this.listen(this, 'mouseleave', 'hide');
- this.listen(this, 'mouseleave', 'unlock');
+ this.addEventListener('mouseleave', this.hide);
+ this.addEventListener('mouseleave', this.unlock);
}
- detached() {
- super.detached();
- this.cancelShowDebouncer();
- this.cancelHideDebouncer();
+ disconnectedCallback() {
+ this.cancelShowTask();
+ this.cancelHideTask();
this.unlock();
+ super.disconnectedCallback();
}
/** @override */
ready() {
super.ready();
// First, check to see if the container has already been created.
- this.container = getRootElement().querySelector('#' + this.containerId);
-
- if (this.container) {
- return;
- }
-
- // If it does not exist, create and initialize the hovercard container.
- this.container = document.createElement('div');
- this.container.setAttribute('id', this.containerId);
- getRootElement().appendChild(this.container);
+ this.container = getHovercardContainer({createIfNotExists: true});
}
removeListeners() {
- this.unlisten(this._target, 'mouseenter', 'debounceShow');
- this.unlisten(this._target, 'focus', 'debounceShow');
- this.unlisten(this._target, 'mouseleave', 'debounceHide');
- this.unlisten(this._target, 'blur', 'debounceHide');
- this.unlisten(this._target, 'click', 'hide');
+ this._target?.removeEventListener('mouseenter', this.debounceShow);
+ this._target?.removeEventListener('focus', this.debounceShow);
+ this._target?.removeEventListener('mouseleave', this.debounceHide);
+ this._target?.removeEventListener('blur', this.debounceHide);
+ this._target?.removeEventListener('click', this.hide);
}
- debounceHide() {
- this.cancelShowDebouncer();
+ readonly debounceHide = () => {
+ this.cancelShowTask();
if (!this._isShowing || this.isScheduledToHide) return;
this.isScheduledToHide = true;
- this.hideDebouncer = Debouncer.debounce(
- this.hideDebouncer,
- timeOut.after(HIDE_DELAY_MS),
+ this.hideTask = debounce(
+ this.hideTask,
() => {
// This happens when hide immediately through click or mouse leave
// on the hovercard
if (!this.isScheduledToHide) return;
this.hide();
- }
+ },
+ HIDE_DELAY_MS
);
- }
+ };
- cancelHideDebouncer() {
- if (this.hideDebouncer) {
- this.hideDebouncer.cancel();
+ cancelHideTask() {
+ if (this.hideTask) {
+ this.hideTask.cancel();
this.isScheduledToHide = false;
}
}
@@ -228,7 +228,7 @@
* Returns the target element that the hovercard is anchored to (the `id` of
* the `for` property).
*/
- get target(): Element {
+ get target(): HTMLElement {
const parentNode = this.parentNode;
// If the parentNode is a document fragment, then we need to use the host.
const ownerRoot = this.getRootNode() as ShadowRoot;
@@ -241,15 +241,15 @@
? ownerRoot.host
: parentNode;
}
- return target as Element;
+ return target as HTMLElement;
}
/**
* unlock scroll, this will resume the scroll outside of the hovercard.
*/
- unlock() {
+ readonly unlock = () => {
removeScrollLock(this);
- }
+ };
/**
* Hides/closes the hovercard. This occurs when the user triggers the
@@ -257,9 +257,9 @@
* user is not hovering over the hovercard).
*
*/
- hide(e?: MouseEvent) {
- this.cancelHideDebouncer();
- this.cancelShowDebouncer();
+ readonly hide = (e?: MouseEvent) => {
+ this.cancelHideTask();
+ this.cancelShowTask();
if (!this._isShowing) {
return;
}
@@ -291,36 +291,36 @@
if (this.container?.contains(this)) {
this.container.removeChild(this);
}
- }
+ };
/**
* Shows/opens the hovercard with a fixed delay.
*/
- debounceShow() {
+ readonly debounceShow = () => {
this.debounceShowBy(SHOW_DELAY_MS);
- }
+ };
/**
* Shows/opens the hovercard with the given delay.
*/
debounceShowBy(delayMs: number) {
- this.cancelHideDebouncer();
+ this.cancelHideTask();
if (this._isShowing || this.isScheduledToShow) return;
this.isScheduledToShow = true;
- this.showDebouncer = Debouncer.debounce(
- this.showDebouncer,
- timeOut.after(delayMs),
+ this.showTask = debounce(
+ this.showTask,
() => {
// This happens when the mouse leaves the target before the delay is over.
if (!this.isScheduledToShow) return;
this.show();
- }
+ },
+ delayMs
);
}
- cancelShowDebouncer() {
- if (this.showDebouncer) {
- this.showDebouncer.cancel();
+ cancelShowTask() {
+ if (this.showTask) {
+ this.showTask.cancel();
this.isScheduledToShow = false;
}
}
@@ -328,17 +328,17 @@
/**
* Lock background scroll but enable scroll inside of current hovercard.
*/
- lock() {
+ readonly lock = () => {
pushScrollLock(this);
- }
+ };
/**
* Shows/opens the hovercard. This occurs when the user triggers the
* `mousenter` event on the hovercard's `target` element.
*/
- show() {
- this.cancelHideDebouncer();
- this.cancelShowDebouncer();
+ readonly show = () => {
+ this.cancelHideTask();
+ this.cancelShowTask();
if (this._isShowing || !this.container) {
return;
}
@@ -359,7 +359,7 @@
flush();
this.updatePosition();
this.classList.remove(HIDE_CLASS);
- }
+ };
updatePosition() {
const positionsToTry = new Set([
@@ -479,16 +479,15 @@
);
export interface GrHovercardBehaviorInterface {
- attached(): void;
ready(): void;
removeListeners(): void;
debounceHide(): void;
- cancelHideDebouncer(): void;
+ cancelHideTask(): void;
dispatchEventThroughTarget(eventName: string, detail?: unknown): void;
hide(e?: MouseEvent): void;
debounceShow(): void;
debounceShowBy(delayMs: number): void;
- cancelShowDebouncer(): void;
+ cancelShowTask(): void;
show(): void;
updatePosition(): void;
updatePositionTo(position: string): void;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
index c56bc8f..8857d36 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
@@ -16,18 +16,14 @@
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard_html';
import {hovercardBehaviorMixin} from './gr-hovercard-behavior';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import './gr-hovercard-shared-style';
import {customElement} from '@polymer/decorators';
@customElement('gr-hovercard')
-export class GrHovercard extends GestureEventListeners(
- hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
-) {
+export class GrHovercard extends hovercardBehaviorMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.js b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.js
index 628b1e9..27ef23f 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.js
@@ -121,7 +121,7 @@
await enterPromise;
assert.isTrue(element.isScheduledToShow);
- element.showDebouncer.flush();
+ element.showTask.flush();
assert.isTrue(element._isShowing);
assert.isFalse(element.isScheduledToShow);
@@ -130,7 +130,7 @@
await leavePromise;
assert.isTrue(element.isScheduledToHide);
assert.isTrue(element._isShowing);
- element.hideDebouncer.flush();
+ element.hideTask.flush();
assert.isFalse(element.isScheduledToShow);
assert.isFalse(element._isShowing);
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
index 7745da8..dc27a49 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
@@ -63,8 +63,6 @@
<g id="hourglass"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"></path><path d="M0 0h24v24H0V0z" fill="none"></path></g>
<!-- This SVG is a copy from material.io https://material.io/icons/#mode_comment-->
<g id="comment"><path d="M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4-.01-18z"></path><path d="M0 0h24v24H0z" fill="none"></path></g>
- <!-- This SVG is a copy from material.io https://material.io/resources/icons/?icon=mode_comment&style=outline-->
- <g id="comment-outline"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M20 17.17L18.83 16H4V4h16v13.17zM20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2z"></path></g>
<!-- This SVG is a copy from material.io https://material.io/icons/#calendar_today-->
<g id="calendar"><path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z"></path><path d="M0 0h24v24H0z" fill="none"></path></g>
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
@@ -130,8 +128,18 @@
<g id="launch"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></g>
<!-- This SVG is a copy from material.io https://material.io/icons/#filter-->
<g id="filter"><path d="M0,0h24 M24,24H0" fill="none"/><path d="M4.25,5.61C6.27,8.2,10,13,10,13v6c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1v-6c0,0,3.72-4.8,5.74-7.39 C20.25,4.95,19.78,4,18.95,4H5.04C4.21,4,3.74,4.95,4.25,5.61z"/><path d="M0,0h24v24H0V0z" fill="none"/></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#arrow_drop_down-->
+ <g id="arrowDropDown"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 10l5 5 5-5z"/></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#arrow_drop_up-->
+ <g id="arrowDropUp"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14l5-5 5 5z"/></g>
<!-- This is just a placeholder, i.e. an empty icon that has the same size as a normal icon. -->
<g id="placeholder"><path d="M0 0h24v24H0z" fill="none"/></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#insert_photo-->
+ <g id="insert-photo"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#download-->
+ <g id="download"><path d="M0 0h24v24H0z" fill="none"/><path d="M5,20h14v-2H5V20z M19,9h-4V3H9v6H5l7,7L19,9z"/></g>
+ <!-- This SVG is a copy from material.io https://material.io/icons/#system_update-->
+ <g id="system-update"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14zm-1-6h-3V8h-2v5H8l4 4 4-4z"/></g>
</defs>
</svg>
</iron-iconset-svg>`;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
deleted file mode 100644
index 9f9ba6a..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {GrAnnotation} from '../../diff/gr-diff-highlight/gr-annotation';
-import {GrStyleObject} from '../../plugins/gr-styles-api/gr-styles-api';
-import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
-import {appContext} from '../../../services/app-context';
-import {AnnotationContext} from '../../../api/annotation';
-
-/**
- * Used to create a context for GrAnnotationActionsInterface.
- *
- * @param contentEl The DIV.contentText element of the line
- * content to apply the annotation to using annotateRange.
- * @param lineNumberEl The TD element of the line number to
- * apply the annotation to using annotateLineNumber.
- * @param line The line object.
- * @param path The file path (eg: '/COMMIT_MSG').
- * @param changeNum The Gerrit change number.
- */
-export class GrAnnotationActionsContext implements AnnotationContext {
- contentEl: HTMLElement;
-
- lineNumberEl: HTMLElement;
-
- line: GrDiffLine;
-
- path: string;
-
- changeNum: number;
-
- private readonly reporting = appContext.reportingService;
-
- constructor(
- contentEl: HTMLElement,
- lineNumberEl: HTMLElement,
- line: GrDiffLine,
- path: string,
- changeNum: string | number
- ) {
- this.contentEl = contentEl;
- this.lineNumberEl = lineNumberEl;
- this.line = line;
- this.path = path;
- this.changeNum = Number(changeNum);
- if (isNaN(this.changeNum)) {
- this.reporting.error(
- new Error(`GrAnnotationActionsContext: Invalid changeNum: ${changeNum}`)
- );
- }
- }
-
- /**
- * Method to add annotations to a content line.
- *
- * @param offset The char offset where the update starts.
- * @param length The number of chars that the update covers.
- * @param styleObject The style object for the range.
- * @param side The side of the update. ('left' or 'right')
- */
- annotateRange(
- offset: number,
- length: number,
- styleObject: GrStyleObject,
- side: string
- ) {
- if (this.contentEl?.getAttribute('data-side') === side) {
- GrAnnotation.annotateElement(
- this.contentEl,
- offset,
- length,
- styleObject.getClassName(this.contentEl)
- );
- }
- }
-
- /**
- * Method to add a CSS class to the line number TD element.
- *
- * @param styleObject The style object for the range.
- * @param side The side of the update. ('left' or 'right')
- */
- annotateLineNumber(styleObject: GrStyleObject, side: string) {
- if (this.lineNumberEl?.classList.contains(side)) {
- styleObject.apply(this.lineNumberEl);
- }
- }
-}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.js
deleted file mode 100644
index b46a3b0..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-js-api-interface.js';
-import {GrAnnotation} from '../../diff/gr-diff-highlight/gr-annotation.js';
-import {GrAnnotationActionsContext} from './gr-annotation-actions-context.js';
-import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-annotation-actions-context tests', () => {
- let instance;
-
- let el;
- let lineNumberEl;
- let plugin;
-
- setup(() => {
- pluginApi.install(p => { plugin = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/test.js');
-
- const str = 'lorem ipsum blah blah';
- const line = {text: str};
- el = document.createElement('div');
- el.textContent = str;
- el.setAttribute('data-side', 'right');
- lineNumberEl = document.createElement('td');
- lineNumberEl.classList.add('right');
- document.body.appendChild(el);
- instance = new GrAnnotationActionsContext(
- el, lineNumberEl, line, 'dummy/path', '123', '1');
- });
-
- teardown(() => {
- el.remove();
- });
-
- test('test annotateRange', () => {
- const annotateElementSpy = sinon.spy(GrAnnotation, 'annotateElement');
- const start = 0;
- const end = 100;
- const cssStyleObject = plugin.styles().css('background-color: #000000');
-
- // Assert annotateElement is not called when side is different.
- instance.annotateRange(start, end, cssStyleObject, 'left');
- assert.equal(annotateElementSpy.callCount, 0);
-
- // Assert annotateElement is called once when side is the same.
- instance.annotateRange(start, end, cssStyleObject, 'right');
- assert.equal(annotateElementSpy.callCount, 1);
- const args = annotateElementSpy.getCalls()[0].args;
- assert.equal(args[0], el);
- assert.equal(args[1], start);
- assert.equal(args[2], end);
- assert.equal(args[3], cssStyleObject.getClassName(el));
- });
-
- test('test annotateLineNumber', () => {
- const cssStyleObject = plugin.styles().css('background-color: #000000');
-
- const className = cssStyleObject.getClassName(lineNumberEl);
-
- // Assert that css class is *not* applied when side is different.
- instance.annotateLineNumber(cssStyleObject, 'left');
- assert.isFalse(lineNumberEl.classList.contains(className));
-
- // Assert that css class is applied when side is the same.
- instance.annotateLineNumber(cssStyleObject, 'right');
- assert.isTrue(lineNumberEl.classList.contains(className));
- });
-});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
index 857d079..3f75970 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
@@ -14,17 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GrAnnotationActionsContext} from './gr-annotation-actions-context';
-import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
import {DiffLayer, DiffLayerListener} from '../../../types/types';
import {Side} from '../../../constants/constants';
import {EventType, PluginApi} from '../../../api/plugin';
import {appContext} from '../../../services/app-context';
-import {
- AnnotationCallback,
- AnnotationPluginApi,
- CoverageProvider,
-} from '../../../api/annotation';
+import {AnnotationPluginApi, CoverageProvider} from '../../../api/annotation';
export class GrAnnotationActionsInterface implements AnnotationPluginApi {
/**
@@ -36,8 +30,6 @@
private coverageProvider?: CoverageProvider;
- private annotationCallback?: AnnotationCallback;
-
private readonly reporting = appContext.reportingService;
constructor(private readonly plugin: PluginApi) {
@@ -45,15 +37,6 @@
plugin.on(EventType.ANNOTATE_DIFF, this);
}
- setLayer(annotationCallback: AnnotationCallback) {
- this.reporting.trackApi(this.plugin, 'annotation', 'setLayer');
- if (this.annotationCallback) {
- console.warn('Overwriting an existing plugin annotation layer.');
- }
- this.annotationCallback = annotationCallback;
- return this;
- }
-
setCoverageProvider(
coverageProvider: CoverageProvider
): GrAnnotationActionsInterface {
@@ -73,40 +56,6 @@
return this.coverageProvider;
}
- enableToggleCheckbox(
- checkboxLabel: string,
- onAttached: (checkboxEl: Element | null) => void
- ) {
- this.reporting.trackApi(this.plugin, 'annotation', 'enableToggleCheckbox');
- this.plugin.hook('annotation-toggler').onAttached(element => {
- if (!element.content) {
- this.reporting.error(new Error('plugin endpoint without content.'));
- return;
- }
- if (!element.content.hidden) {
- this.reporting.error(
- new Error(
- `${element.content.id} is already enabled. Cannot re-enable.`
- )
- );
- return;
- }
- element.content.removeAttribute('hidden');
-
- const label = element.content.querySelector('#annotation-label');
- if (label) {
- if (checkboxLabel) {
- label.textContent = checkboxLabel;
- } else {
- label.textContent = 'Enable';
- }
- }
- const checkbox = element.content.querySelector('#annotation-checkbox');
- onAttached(checkbox);
- });
- return this;
- }
-
notify(path: string, start: number, end: number, side: Side) {
this.reporting.trackApi(this.plugin, 'annotation', 'notify');
for (const annotationLayer of this.annotationLayers) {
@@ -124,9 +73,8 @@
*
* Don't forget to also call disposeLayer().
*/
- createLayer(path: string, changeNum: number) {
- const callbackFn = this.annotationCallback || (() => {});
- const annotationLayer = new AnnotationLayer(path, changeNum, callbackFn);
+ createLayer(path: string) {
+ const annotationLayer = new AnnotationLayer(path);
this.annotationLayers.push(annotationLayer);
return annotationLayer;
}
@@ -152,15 +100,8 @@
* Used to create an instance of the Annotation Layer interface.
*
* @param path The file path (eg: /COMMIT_MSG').
- * @param changeNum The Gerrit change number.
- * @param annotationCallback The function
- * that will be called when the AnnotationLayer is ready to annotate.
*/
- constructor(
- readonly path: string,
- private readonly changeNum: number,
- private readonly annotationCallback: AnnotationCallback
- ) {
+ constructor(readonly path: string) {
this.listeners = [];
}
@@ -180,30 +121,7 @@
this.listeners = this.listeners.filter(f => f !== listener);
}
- /**
- * Called by Gerrit during diff rendering for each line. Delegates to the
- * plugin provided callback for potentially annotating this line.
- *
- * @param contentEl The DIV.contentText element of the line
- * content to apply the annotation to using annotateRange.
- * @param lineNumberEl The TD element of the line number to
- * apply the annotation to using annotateLineNumber.
- * @param line The line object.
- */
- annotate(
- contentEl: HTMLElement,
- lineNumberEl: HTMLElement,
- line: GrDiffLine
- ) {
- const context = new GrAnnotationActionsContext(
- contentEl,
- lineNumberEl,
- line,
- this.path,
- this.changeNum
- );
- this.annotationCallback(context);
- }
+ annotate() {}
/**
* Notify layer listeners (which typically is just Gerrit's diff renderer) of
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.js
index 9811f99..996edf3 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.js
@@ -18,16 +18,6 @@
import '../../../test/common-test-setup-karma.js';
import '../../change/gr-change-actions/gr-change-actions.js';
import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
- <span hidden id="annotation-span">
- <label for="annotation-checkbox" id="annotation-label"></label>
- <iron-input type="checkbox" disabled>
- <input is="iron-input" type="checkbox" id="annotation-checkbox" disabled>
- </iron-input>
- </span>
-`);
const pluginApi = _testOnly_initGerritPluginApi();
@@ -46,33 +36,9 @@
annotationActions = null;
});
- test('add/get layer', () => {
- const str = 'lorem ipsum blah blah';
- const line = {text: str};
- const el = document.createElement('div');
- el.textContent = str;
- const changeNum = 1234;
- let testLayerFuncCalled = false;
-
- const testLayerFunc = context => {
- testLayerFuncCalled = true;
- assert.equal(context.line, line);
- assert.equal(context.changeNum, changeNum);
- };
- annotationActions.setLayer(testLayerFunc);
-
- const annotationLayer = annotationActions.createLayer(
- '/dummy/path', changeNum);
-
- const lineNumberEl = document.createElement('td');
- annotationLayer.annotate(el, lineNumberEl, line);
- assert.isTrue(testLayerFuncCalled);
- });
-
test('add notifier', () => {
const path1 = '/dummy/path1';
const path2 = '/dummy/path2';
- annotationActions.setLayer(context => {});
const annotationLayer1 = annotationActions.createLayer(path1, 1);
const annotationLayer2 = annotationActions.createLayer(path2, 1);
const layer1Spy = sinon.spy(annotationLayer1, 'notifyListeners');
@@ -98,44 +64,7 @@
assert.isTrue(layer2Spy.called);
});
- test('toggle checkbox', () => {
- const fakeEl = {content: basicFixture.instantiate()};
- const hookStub = {onAttached: sinon.stub()};
- sinon.stub(plugin, 'hook').returns(hookStub);
-
- let checkbox;
- let onAttachedFuncCalled = false;
- const onAttachedFunc = c => {
- checkbox = c;
- onAttachedFuncCalled = true;
- };
- annotationActions.enableToggleCheckbox('test label', onAttachedFunc);
- const emulateAttached = () => hookStub.onAttached.callArgWith(0, fakeEl);
- emulateAttached();
-
- // Assert that onAttachedFunc is called and HTML elements have the
- // expected state.
- assert.isTrue(onAttachedFuncCalled);
- assert.equal(checkbox.id, 'annotation-checkbox');
- assert.isTrue(checkbox.disabled);
- assert.equal(document.getElementById('annotation-label').textContent,
- 'test label');
- assert.isFalse(document.getElementById('annotation-span').hidden);
-
- // Assert that error is shown if we try to enable checkbox again.
- onAttachedFuncCalled = false;
- annotationActions.enableToggleCheckbox('test label2', onAttachedFunc);
- const errorStub = sinon.stub(annotationActions.reporting, 'error');
- emulateAttached();
- assert.isTrue(errorStub.called);
- // Assert that onAttachedFunc is not called and the label has not changed.
- assert.isFalse(onAttachedFuncCalled);
- assert.equal(document.getElementById('annotation-label').textContent,
- 'test label');
- });
-
test('layer notify listeners', () => {
- annotationActions.setLayer(context => {});
const annotationLayer = annotationActions.createLayer('/dummy/path', 1);
let listenerCalledTimes = 0;
const startRange = 10;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils.ts
index 979b86e..db127f3 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils.ts
@@ -59,9 +59,9 @@
}
// Pathname should normally look like this:
- // /plugins/PLUGINNAME/static/SCRIPTNAME.html
+ // /plugins/PLUGINNAME/static/SCRIPTNAME.js
// Or, for app/samples:
- // /plugins/PLUGINNAME.html
+ // /plugins/PLUGINNAME.js
// TODO(taoalpha): guard with a regex
return pathname.split('/')[2].split('.')[0];
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js
index 85c62cb..a09d887 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js
@@ -34,18 +34,18 @@
test('with random invalid url', () => {
assert.equal(getPluginNameFromUrl('http://example.com'), null);
assert.equal(
- getPluginNameFromUrl('http://example.com/static/a.html'),
+ getPluginNameFromUrl('http://example.com/static/a.js'),
null
);
});
test('with valid urls', () => {
assert.equal(
- getPluginNameFromUrl('http://example.com/plugins/a.html'),
+ getPluginNameFromUrl('http://example.com/plugins/a.js'),
'a'
);
assert.equal(
- getPluginNameFromUrl('http://example.com/plugins/a/static/t.html'),
+ getPluginNameFromUrl('http://example.com/plugins/a/static/t.js'),
'a'
);
});
@@ -56,7 +56,7 @@
test('with gerrit-theme override', () => {
assert.equal(
- getPluginNameFromUrl('http://example.com/static/gerrit-theme.html'),
+ getPluginNameFromUrl('http://example.com/static/gerrit-theme.js'),
'gerrit-theme'
);
});
@@ -64,7 +64,7 @@
test('with ASSETS_PATH', () => {
window.ASSETS_PATH = 'http://cdn.com/2';
assert.equal(
- getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.html`),
+ getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.js`),
'a'
);
window.ASSETS_PATH = undefined;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
index de57794..fc5a4aa 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
@@ -56,11 +56,6 @@
this._el.setLabelValue(label, value);
}
- send(includeComments?: boolean) {
- this.reporting.trackApi(this.plugin, 'reply', 'send');
- this._el.send(includeComments);
- }
-
addReplyTextChangedCallback(handler: ReplyChangedCallback) {
this.reporting.trackApi(this.plugin, 'reply', 'addReplyTextChangedCb');
const hookApi = this.plugin.hook('reply-text');
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.js
index 52efc56..2324588 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.js
@@ -31,7 +31,6 @@
let plugin;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getAccount').returns(Promise.resolve(null));
});
@@ -56,10 +55,6 @@
assert.isTrue(
element.setLabelValue.calledWithExactly('My-Label', '+1337'));
- sinon.stub(element, 'send');
- changeReply.send(false);
- assert.isTrue(element.send.calledWithExactly(false));
-
sinon.stub(element, 'setPluginMessage');
changeReply.showMessage('foobar');
assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
@@ -87,10 +82,6 @@
assert.isTrue(
element.setLabelValue.calledWithExactly('My-Label', '+1337'));
- sinon.stub(element, 'send');
- changeReply.send(false);
- assert.isTrue(element.send.calledWithExactly(false));
-
sinon.stub(element, 'setPluginMessage');
changeReply.showMessage('foobar');
assert.isTrue(element.setPluginMessage.calledWithExactly('foobar'));
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
index 7f9218a..7afdd20 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
@@ -19,11 +19,7 @@
* This defines the Gerrit instance. All methods directly attached to Gerrit
* should be defined or linked here.
*/
-import {
- getPluginLoader,
- PluginOptionMap,
- PluginLoader,
-} from './gr-plugin-loader';
+import {getPluginLoader, PluginOptionMap} from './gr-plugin-loader';
import {send} from './gr-api-utils';
import {appContext} from '../../../services/app-context';
import {PluginApi} from '../../../api/plugin';
@@ -34,15 +30,8 @@
EventEmitterService,
} from '../../../services/gr-event-interface/gr-event-interface';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import {getRootElement} from '../../../scripts/rootElement';
-import {GrPluginEndpoints} from './gr-plugin-endpoints';
-import {rangesEqual} from '../../diff/gr-diff/gr-diff-utils';
-import {SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../../../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider';
-import {CoverageType} from '../../../types/types';
-import {RevisionInfo} from '../revision-info/revision-info';
export interface GerritGlobal extends EventEmitterService {
- flushPreinstalls?(): void;
css(rule: string): string;
install(
callback: (plugin: PluginApi) => void,
@@ -75,31 +64,10 @@
// exposed methods
Nav: typeof GerritNav;
Auth: typeof appContext.authService;
- getRootElement: typeof getRootElement;
- _pluginLoader: PluginLoader;
- _endpoints: GrPluginEndpoints;
- slotToContent(slot: unknown): unknown;
- rangesEqual: typeof rangesEqual;
- SUGGESTIONS_PROVIDERS_USERS_TYPES: typeof SUGGESTIONS_PROVIDERS_USERS_TYPES;
- CoverageType: typeof CoverageType;
- RevisionInfo: typeof RevisionInfo;
}
-/**
- * Trigger the preinstalls for bundled plugins.
- * This needs to happen before Gerrit as plugin bundle overrides the Gerrit.
- */
-function flushPreinstalls() {
- const Gerrit = window.Gerrit;
- if (Gerrit?.flushPreinstalls) {
- Gerrit.flushPreinstalls();
- }
-}
-export const _testOnly_flushPreinstalls = flushPreinstalls;
-
export function initGerritPluginApi() {
window.Gerrit = window.Gerrit || {};
- flushPreinstalls();
initGerritPluginsMethods(window.Gerrit as GerritGlobal);
// Preloaded plugins should be installed after Gerrit.install() is set,
// since plugin preloader substitutes Gerrit.install() temporarily.
@@ -135,12 +103,17 @@
});
}
+const fakeApi = {
+ getPluginName: () => 'global',
+};
+
function initGerritPluginsMethods(globalGerritObj: GerritGlobal) {
/**
* @deprecated Use plugin.styles().css(rulesStr) instead. Please, consult
* the documentation how to replace it accordingly.
*/
globalGerritObj.css = (rulesStr: string) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'css');
console.warn(
'Gerrit.css(rulesStr) is deprecated!',
'Use plugin.styles().css(rulesStr)'
@@ -164,6 +137,7 @@
};
globalGerritObj.getLoggedIn = () => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'getLoggedIn');
console.warn(
'Gerrit.getLoggedIn() is deprecated! ' +
'Use plugin.restApi().getLoggedIn()'
@@ -175,6 +149,7 @@
url: string,
callback?: (response: unknown) => void
) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'get');
console.warn('.get() is deprecated! Use plugin.restApi().get()');
send(HttpMethod.GET, url, callback);
};
@@ -184,6 +159,7 @@
payload?: RequestPayload,
callback?: (response: unknown) => void
) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'post');
console.warn('.post() is deprecated! Use plugin.restApi().post()');
send(HttpMethod.POST, url, callback, payload);
};
@@ -193,6 +169,7 @@
payload?: RequestPayload,
callback?: (response: unknown) => void
) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'put');
console.warn('.put() is deprecated! Use plugin.restApi().put()');
send(HttpMethod.PUT, url, callback, payload);
};
@@ -201,32 +178,51 @@
url: string,
callback?: (response: Response) => void
) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'delete');
deprecatedDelete(url, callback);
};
globalGerritObj.awaitPluginsLoaded = () => {
+ appContext.reportingService.trackApi(
+ fakeApi,
+ 'global',
+ 'awaitPluginsLoaded'
+ );
return getPluginLoader().awaitPluginsLoaded();
};
// TODO(taoalpha): consider removing these proxy methods
// and using getPluginLoader() directly
- globalGerritObj._loadPlugins = (plugins, opt_option) => {
- getPluginLoader().loadPlugins(plugins, opt_option);
+ globalGerritObj._loadPlugins = plugins => {
+ appContext.reportingService.trackApi(fakeApi, 'global', '_loadPlugins');
+ getPluginLoader().loadPlugins(plugins);
};
globalGerritObj._arePluginsLoaded = () => {
+ appContext.reportingService.trackApi(
+ fakeApi,
+ 'global',
+ '_arePluginsLoaded'
+ );
return getPluginLoader().arePluginsLoaded();
};
globalGerritObj._isPluginPreloaded = url => {
+ appContext.reportingService.trackApi(
+ fakeApi,
+ 'global',
+ '_isPluginPreloaded'
+ );
return getPluginLoader().isPluginPreloaded(url);
};
globalGerritObj._isPluginEnabled = pathOrUrl => {
+ appContext.reportingService.trackApi(fakeApi, 'global', '_isPluginEnabled');
return getPluginLoader().isPluginEnabled(pathOrUrl);
};
globalGerritObj._isPluginLoaded = pathOrUrl => {
+ appContext.reportingService.trackApi(fakeApi, 'global', '_isPluginLoaded');
return getPluginLoader().isPluginLoaded(pathOrUrl);
};
@@ -257,22 +253,42 @@
* });
* });
*/
- globalGerritObj.addListener = (eventName: string, cb: EventCallback) =>
- eventEmitter.addListener(eventName, cb);
+ globalGerritObj.addListener = (eventName: string, cb: EventCallback) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'addListener');
+ return eventEmitter.addListener(eventName, cb);
+ };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- globalGerritObj.dispatch = (eventName: string, detail: any) =>
- eventEmitter.dispatch(eventName, detail);
+ globalGerritObj.dispatch = (eventName: string, detail: any) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'dispatch');
+ return eventEmitter.dispatch(eventName, detail);
+ };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- globalGerritObj.emit = (eventName: string, detail: any) =>
- eventEmitter.emit(eventName, detail);
- globalGerritObj.off = (eventName: string, cb: EventCallback) =>
- eventEmitter.off(eventName, cb);
- globalGerritObj.on = (eventName: string, cb: EventCallback) =>
- eventEmitter.on(eventName, cb);
- globalGerritObj.once = (eventName: string, cb: EventCallback) =>
- eventEmitter.once(eventName, cb);
- globalGerritObj.removeAllListeners = (eventName: string) =>
- eventEmitter.removeAllListeners(eventName);
- globalGerritObj.removeListener = (eventName: string, cb: EventCallback) =>
- eventEmitter.removeListener(eventName, cb);
+ globalGerritObj.emit = (eventName: string, detail: any) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'emit');
+ return eventEmitter.emit(eventName, detail);
+ };
+ globalGerritObj.off = (eventName: string, cb: EventCallback) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'off');
+ return eventEmitter.off(eventName, cb);
+ };
+ globalGerritObj.on = (eventName: string, cb: EventCallback) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'on');
+ return eventEmitter.on(eventName, cb);
+ };
+ globalGerritObj.once = (eventName: string, cb: EventCallback) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'once');
+ return eventEmitter.once(eventName, cb);
+ };
+ globalGerritObj.removeAllListeners = (eventName: string) => {
+ appContext.reportingService.trackApi(
+ fakeApi,
+ 'global',
+ 'removeAllListeners'
+ );
+ return eventEmitter.removeAllListeners(eventName);
+ };
+ globalGerritObj.removeListener = (eventName: string, cb: EventCallback) => {
+ appContext.reportingService.trackApi(fakeApi, 'global', 'removeListener');
+ return eventEmitter.removeListener(eventName, cb);
+ };
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
index 8689ad2..95d2e7f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
@@ -247,12 +247,12 @@
return revertSubmissionMsg;
}
- getDiffLayers(path: string, changeNum: number) {
+ getDiffLayers(path: string) {
const layers: DiffLayer[] = [];
for (const cb of this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
const annotationApi = (cb as unknown) as GrAnnotationActionsInterface;
try {
- const layer = annotationApi.createLayer(path, changeNum);
+ const layer = annotationApi.createLayer(path);
if (layer) layers.push(layer);
} catch (err) {
this.reporting.error(err);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
index 12a4056..a9bb8ae 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
@@ -18,7 +18,6 @@
import '../../../test/common-test-setup-karma.js';
import './gr-js-api-interface.js';
import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface.js';
-import {GrSettingsApi} from '../../plugins/gr-settings-api/gr-settings-api.js';
import {EventType} from '../../../api/plugin.js';
import {PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils.js';
import {getPluginLoader} from './gr-plugin-loader.js';
@@ -35,7 +34,6 @@
let plugin;
let errorStub;
- let getResponseObjectStub;
let sendStub;
let clock;
@@ -47,8 +45,6 @@
clock = sinon.useFakeTimers();
stubRestApi('getAccount').returns(Promise.resolve({name: 'Judy Hopps'}));
- getResponseObjectStub = stubRestApi('getResponseObject').returns(
- Promise.resolve());
sendStub = stubRestApi('send').returns(Promise.resolve({status: 200}));
element = appContext.jsApiService;
errorStub = sinon.stub(element.reporting, 'error');
@@ -107,76 +103,6 @@
});
});
- test('get', () => {
- const response = {foo: 'foo'};
- getResponseObjectStub.returns(Promise.resolve(response));
- return plugin.get('/url', r => {
- assert.isTrue(sendStub.calledWith(
- 'GET', 'http://test.com/plugins/testplugin/url'));
- assert.strictEqual(r, response);
- });
- });
-
- test('get using Promise', () => {
- const response = {foo: 'foo'};
- getResponseObjectStub.returns(Promise.resolve(response));
- return plugin.get('/url', r => 'rubbish').then(r => {
- assert.isTrue(sendStub.calledWith(
- 'GET', 'http://test.com/plugins/testplugin/url'));
- assert.strictEqual(r, response);
- });
- });
-
- test('post', () => {
- const payload = {foo: 'foo'};
- const response = {bar: 'bar'};
- getResponseObjectStub.returns(Promise.resolve(response));
- return plugin.post('/url', payload, r => {
- assert.isTrue(sendStub.calledWith(
- 'POST', 'http://test.com/plugins/testplugin/url', payload));
- assert.strictEqual(r, response);
- });
- });
-
- test('put', () => {
- const payload = {foo: 'foo'};
- const response = {bar: 'bar'};
- getResponseObjectStub.returns(Promise.resolve(response));
- return plugin.put('/url', payload, r => {
- assert.isTrue(sendStub.calledWith(
- 'PUT', 'http://test.com/plugins/testplugin/url', payload));
- assert.strictEqual(r, response);
- });
- });
-
- test('delete works', () => {
- const response = {status: 204};
- sendStub.returns(Promise.resolve(response));
- return plugin.delete('/url', r => {
- assert.equal(sendStub.lastCall.args[0], 'DELETE');
- assert.equal(
- sendStub.lastCall.args[1],
- 'http://test.com/plugins/testplugin/url'
- );
- assert.strictEqual(r, response);
- });
- });
-
- test('delete fails', () => {
- sendStub.returns(Promise.resolve(
- {status: 400, text() { return Promise.resolve('text'); }}));
- return plugin.delete('/url', r => {
- throw new Error('Should not resolve');
- }).catch(err => {
- assert.equal(sendStub.lastCall.args[0], 'DELETE');
- assert.equal(
- sendStub.lastCall.args[1],
- 'http://test.com/plugins/testplugin/url'
- );
- assert.equal('text', err.message);
- });
- });
-
test('history event', async () => {
let resolve;
const promise = new Promise(r => resolve = r);
@@ -236,7 +162,7 @@
revisions: {def: {_number: 2}, abc: {_number: 1}},
};
const spy = sinon.spy();
- getPluginLoader().loadPlugins(['plugins/test.html']);
+ getPluginLoader().loadPlugins(['plugins/test.js']);
plugin.on(EventType.SHOW_CHANGE, spy);
element.handleEvent(EventType.SHOW_CHANGE,
{change: testChange, patchNum: 1});
@@ -453,12 +379,5 @@
'testplugin-screen-foo', 'some-module'));
});
});
-
- suite('settingsScreen', () => {
- test('plugin.settings() returns GrSettingsApi', () => {
- assert.isOk(plugin.settings());
- assert.isTrue(plugin.settings() instanceof GrSettingsApi);
- });
- });
});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
index 0b28c5e..9644ef3 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
@@ -56,7 +56,7 @@
origMsg: string
): string;
addElement(key: TargetElement, el: HTMLElement): void;
- getDiffLayers(path: string, changeNum: number): DiffLayer[];
+ getDiffLayers(path: string): DiffLayer[];
disposeDiffLayers(path: string): void;
getCoverageAnnotationApis(): Promise<GrAnnotationActionsInterface[]>;
getAdminMenuLinks(): MenuLink[];
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
index 82df2fa..0cc95a3 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import {importHref} from '../../../scripts/import-href';
import {PluginApi} from '../../../api/plugin';
import {notUndefined} from '../../../types/types';
import {HookApi} from '../../../api/hook';
@@ -49,8 +47,6 @@
private readonly _dynamicPlugins = new Map<string, Set<string>>();
- private readonly _importedUrls = new Set<string>();
-
private pluginLoaded = false;
setPluginsReady() {
@@ -179,43 +175,6 @@
notUndefined
);
}
-
- importUrl(pluginUrl: URL) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let timerId: any;
- return Promise.race([
- new Promise((resolve, reject) => {
- this._importedUrls.add(pluginUrl.href);
- importHref(pluginUrl.href, resolve, reject);
- }),
- // Timeout after 3s
- new Promise(r => (timerId = setTimeout(r, 3000))),
- ]).finally(() => {
- if (timerId) clearTimeout(timerId);
- });
- }
-
- /**
- * Get plugin URLs with element and module definitions.
- */
- getAndImportPlugins(name: string, options?: Options) {
- return Promise.all(
- this.getPlugins(name, options).map(pluginUrl => {
- if (this._importedUrls.has(pluginUrl.href)) {
- return Promise.resolve();
- }
-
- // TODO: we will deprecate html plugins entirely
- // for now, keep the original behavior and import
- // only for html ones
- if (pluginUrl?.pathname.endsWith('.html')) {
- return this.importUrl(pluginUrl);
- } else {
- return Promise.resolve();
- }
- })
- );
- }
}
// TODO(dmfilippov): Convert to service and add to appContext
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
index 5b931b4..e3475ad 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
@@ -33,7 +33,7 @@
domHook = {};
instance = new GrPluginEndpoints();
pluginApi.install(p => { pluginFoo = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/foo.html');
+ 'http://test.com/plugins/testplugin/static/foo.js');
instance.registerModule(
pluginFoo,
{
@@ -44,7 +44,7 @@
}
);
pluginApi.install(p => { pluginBar = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/bar.html');
+ 'http://test.com/plugins/testplugin/static/bar.js');
instance.registerModule(
pluginBar,
{
@@ -54,7 +54,6 @@
domHook,
}
);
- sinon.spy(instance, 'importUrl');
});
teardown(() => {
@@ -120,14 +119,6 @@
instance.getPlugins('a-place'), [pluginFoo._url]);
});
- test('getAndImportPlugins', () => {
- instance.getAndImportPlugins('a-place');
- assert.isTrue(instance.importUrl.called);
- assert.isTrue(instance.importUrl.calledOnce);
- instance.getAndImportPlugins('a-place');
- assert.isTrue(instance.importUrl.calledOnce);
- });
-
test('onNewEndpoint', () => {
const newModuleStub = sinon.stub();
instance.setPluginsReady();
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
index db34e5a..85b6747 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
@@ -15,7 +15,6 @@
* limitations under the License.
*/
import {appContext} from '../../../services/app-context';
-import {importHref} from '../../../scripts/import-href';
import {
PLUGIN_LOADING_TIMEOUT_MS,
PRELOADED_PROTOCOL,
@@ -69,8 +68,8 @@
// Prefix for any unrecognized plugin urls.
// Url should match following patterns:
-// /plugins/PLUGINNAME/static/SCRIPTNAME.(html|js)
-// /plugins/PLUGINNAME.(js|html)
+// /plugins/PLUGINNAME/static/SCRIPTNAME.js
+// /plugins/PLUGINNAME.js
const UNKNOWN_PLUGIN_PREFIX = '__$$__';
// Current API version for Plugin,
@@ -116,7 +115,7 @@
/**
* Load multiple plugins with certain options.
*/
- loadPlugins(plugins: string[] = [], opts: PluginOptionMap = {}) {
+ loadPlugins(plugins: string[] = []) {
this._pluginListLoaded = true;
plugins.forEach(path => {
@@ -134,9 +133,7 @@
plugin: null,
});
- if (this._isPathEndsWith(url, '.html')) {
- this._importHtmlPlugin(path, opts && opts[path]);
- } else if (this._isPathEndsWith(url, '.js')) {
+ if (this._isPathEndsWith(url, '.js')) {
this._loadJsPlugin(path);
} else {
this._failToLoad(`Unrecognized plugin path ${path}`, path);
@@ -336,27 +333,6 @@
: false;
}
- _importHtmlPlugin(pluginUrl: string, opts: PluginOption = {}) {
- const urlWithAP = this._urlFor(pluginUrl, window.ASSETS_PATH);
- const urlWithoutAP = this._urlFor(pluginUrl);
- let onerror = undefined;
- this._getReporting().reportExecution('html-plugin', {pluginUrl});
- if (urlWithAP !== urlWithoutAP) {
- onerror = () => this._loadHtmlPlugin(urlWithoutAP, opts.sync);
- }
- this._loadHtmlPlugin(urlWithAP, opts.sync, onerror);
- }
-
- _loadHtmlPlugin(url: string, sync?: boolean, onerror?: (e: Event) => void) {
- if (!onerror) {
- onerror = () => {
- this._failToLoad(`${url} import error`, url);
- };
- }
-
- importHref(url, () => {}, onerror, !sync);
- }
-
_loadJsPlugin(pluginUrl: string) {
const urlWithAP = this._urlFor(pluginUrl, window.ASSETS_PATH);
const urlWithoutAP = this._urlFor(pluginUrl);
@@ -386,9 +362,7 @@
_urlFor(pathOrUrl: string, assetsPath?: string): string {
// theme is per host, should always load from assetsPath
- const isThemeFile =
- pathOrUrl.endsWith('static/gerrit-theme.html') ||
- pathOrUrl.endsWith('static/gerrit-theme.js');
+ const isThemeFile = pathOrUrl.endsWith('static/gerrit-theme.js');
const shouldTryLoadFromAssetsPathFirst = !isThemeFile && assetsPath;
if (
pathOrUrl.startsWith(PRELOADED_PROTOCOL) ||
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
index f5b1fca..1ca7e75 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader_test.js
@@ -19,7 +19,6 @@
import {PRELOADED_PROTOCOL, PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils.js';
import {_testOnly_resetPluginLoader} from './gr-plugin-loader.js';
import {resetPlugins, stubBaseUrl} from '../../../test/test-utils.js';
-import {_testOnly_flushPreinstalls} from './gr-gerrit.js';
import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
@@ -57,16 +56,6 @@
assert.strictEqual(plugin, otherPlugin);
});
- test('flushes preinstalls if provided', () => {
- assert.doesNotThrow(() => {
- _testOnly_flushPreinstalls();
- });
- window.Gerrit.flushPreinstalls = sinon.stub();
- _testOnly_flushPreinstalls();
- assert.isTrue(window.Gerrit.flushPreinstalls.calledOnce);
- delete window.Gerrit.flushPreinstalls;
- });
-
test('versioning', () => {
const callback = sinon.spy();
pluginApi.install(callback, '0.0pre-alpha');
@@ -270,13 +259,8 @@
});
suite('plugin path and url', () => {
- let importHtmlPluginStub;
let loadJsPluginStub;
setup(() => {
- importHtmlPluginStub = sinon.stub();
- sinon.stub(pluginLoader, '_loadHtmlPlugin').callsFake( url => {
- importHtmlPluginStub(url);
- });
loadJsPluginStub = sinon.stub();
sinon.stub(pluginLoader, '_createScriptTag').callsFake( url => {
loadJsPluginStub(url);
@@ -303,13 +287,8 @@
test('relative path for plugins', () => {
pluginLoader.loadPlugins([
'foo/bar.js',
- 'foo/bar.html',
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
- assert.isTrue(
- importHtmlPluginStub.calledWithExactly(`${url}/foo/bar.html`)
- );
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
loadJsPluginStub.calledWithExactly(`${url}/foo/bar.js`)
@@ -322,17 +301,10 @@
pluginLoader.loadPlugins([
'foo/bar.js',
- 'foo/bar.html',
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
- importHtmlPluginStub.calledWithExactly(
- `${url}${testUrl}/foo/bar.html`
- )
- );
- assert.isTrue(
loadJsPluginStub.calledWithExactly(`${url}${testUrl}/foo/bar.js`)
);
});
@@ -340,13 +312,8 @@
test('absolute path for plugins', () => {
pluginLoader.loadPlugins([
'http://e.com/foo/bar.js',
- 'http://e.com/foo/bar.html',
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
- assert.isTrue(
- importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
- );
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`)
@@ -355,14 +322,9 @@
});
suite('With ASSETS_PATH', () => {
- let importHtmlPluginStub;
let loadJsPluginStub;
setup(() => {
window.ASSETS_PATH = 'https://cdn.com';
- importHtmlPluginStub = sinon.stub();
- sinon.stub(pluginLoader, '_loadHtmlPlugin').callsFake( url => {
- importHtmlPluginStub(url);
- });
loadJsPluginStub = sinon.stub();
sinon.stub(pluginLoader, '_createScriptTag').callsFake( url => {
loadJsPluginStub(url);
@@ -376,13 +338,8 @@
test('Should try load plugins from assets path instead', () => {
pluginLoader.loadPlugins([
'foo/bar.js',
- 'foo/bar.html',
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
- assert.isTrue(
- importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
- );
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
@@ -390,14 +347,9 @@
test('Should honor original path if exists', () => {
pluginLoader.loadPlugins([
- 'http://e.com/foo/bar.html',
'http://e.com/foo/bar.js',
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
- assert.isTrue(
- importHtmlPluginStub.calledWithExactly(`http://e.com/foo/bar.html`)
- );
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
loadJsPluginStub.calledWithExactly(`http://e.com/foo/bar.js`));
@@ -406,14 +358,9 @@
test('Should try replace current host with assetsPath', () => {
const host = window.location.origin;
pluginLoader.loadPlugins([
- `${host}/foo/bar.html`,
`${host}/foo/bar.js`,
]);
- assert.isTrue(importHtmlPluginStub.calledOnce);
- assert.isTrue(
- importHtmlPluginStub.calledWithExactly(`https://cdn.com/foo/bar.html`)
- );
assert.isTrue(loadJsPluginStub.calledOnce);
assert.isTrue(
loadJsPluginStub.calledWithExactly(`https://cdn.com/foo/bar.js`));
@@ -456,10 +403,6 @@
window.Gerrit._preloadedPlugins = null;
});
test('skips preloaded plugins when load plugins', () => {
- const importHtmlPluginStub = sinon.stub();
- sinon.stub(pluginLoader, '_importHtmlPlugin').callsFake( url => {
- importHtmlPluginStub(url);
- });
const loadJsPluginStub = sinon.stub();
sinon.stub(pluginLoader, '_loadJsPlugin').callsFake( url => {
loadJsPluginStub(url);
@@ -472,11 +415,9 @@
pluginLoader.loadPlugins([
'http://e.com/plugins/foo.js',
- 'plugins/bar.html',
'http://e.com/plugins/test/foo.js',
]);
- assert.isTrue(importHtmlPluginStub.notCalled);
assert.isTrue(loadJsPluginStub.calledOnce);
});
@@ -502,8 +443,8 @@
let plugin;
pluginApi.install(p => { plugin = p; }, '0.1', 'preloaded:foo');
assert.strictEqual(plugin.getPluginName(), 'foo');
- assert.strictEqual(plugin.url('/some/thing.html'),
- `${window.location.origin}/plugins/foo/some/thing.html`);
+ assert.strictEqual(plugin.url('/some/thing.js'),
+ `${window.location.origin}/plugins/foo/some/thing.js`);
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
index 68fb96b..6ff9a50 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
@@ -14,24 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import {getBaseUrl} from '../../../utils/url-util';
import {GrAttributeHelper} from '../../plugins/gr-attribute-helper/gr-attribute-helper';
import {GrChangeActionsInterface} from './gr-change-actions-js-api';
import {GrChangeReplyInterface} from './gr-change-reply-js-api';
import {GrDomHooksManager} from '../../plugins/gr-dom-hooks/gr-dom-hooks';
-import {GrThemeApi} from '../../plugins/gr-theme-api/gr-theme-api';
import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface';
import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {GrChangeMetadataApi} from '../../plugins/gr-change-metadata-api/gr-change-metadata-api';
import {GrEventHelper} from '../../plugins/gr-event-helper/gr-event-helper';
import {GrPluginRestApi} from './gr-plugin-rest-api';
-import {GrRepoApi} from '../../plugins/gr-repo-api/gr-repo-api';
-import {GrSettingsApi} from '../../plugins/gr-settings-api/gr-settings-api';
-import {GrStylesApi} from '../../plugins/gr-styles-api/gr-styles-api';
import {getPluginEndpoints} from './gr-plugin-endpoints';
-
import {getPluginNameFromUrl, PRELOADED_PROTOCOL, send} from './gr-api-utils';
import {GrReportingJsApi} from './gr-reporting-js-api';
import {EventType, PluginApi, TargetElement} from '../../../api/plugin';
@@ -42,15 +35,10 @@
import {appContext} from '../../../services/app-context';
import {AdminPluginApi} from '../../../api/admin';
import {AnnotationPluginApi} from '../../../api/annotation';
-import {StylesPluginApi} from '../../../api/styles';
-import {ThemePluginApi} from '../../../api/theme';
import {EventHelperPluginApi} from '../../../api/event-helper';
import {PopupPluginApi} from '../../../api/popup';
-import {SettingsPluginApi} from '../../../api/settings';
import {ReportingPluginApi} from '../../../api/reporting';
import {ChangeActionsPluginApi} from '../../../api/change-actions';
-import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
-import {RepoPluginApi} from '../../../api/repo';
import {ChangeReplyPluginApi} from '../../../api/change-reply';
import {RestPluginApi} from '../../../api/rest';
import {HookApi, RegisterOptions} from '../../../api/hook';
@@ -227,35 +215,6 @@
return send(method, this.url(url), callback, payload);
}
- get(url: string, callback?: SendCallback) {
- this.report.trackApi(this, 'plugin', 'get');
- console.warn('.get() is deprecated! Use .restApi().get()');
- return this._send(HttpMethod.GET, url, callback);
- }
-
- post(url: string, payload: RequestPayload, callback?: SendCallback) {
- this.report.trackApi(this, 'plugin', 'post');
- console.warn('.post() is deprecated! Use .restApi().post()');
- return this._send(HttpMethod.POST, url, callback, payload);
- }
-
- put(url: string, payload: RequestPayload, callback?: SendCallback) {
- this.report.trackApi(this, 'plugin', 'put');
- console.warn('.put() is deprecated! Use .restApi().put()');
- return this._send(HttpMethod.PUT, url, callback, payload);
- }
-
- delete(url: string, callback?: SendCallback) {
- this.report.trackApi(this, 'plugin', 'delete');
- console.warn('.delete() is deprecated! Use plugin.restApi().delete()');
- return this.restApi()
- .delete(this.url(url))
- .then(res => {
- if (callback) callback(res);
- return res;
- });
- }
-
annotationApi(): AnnotationPluginApi {
return new GrAnnotationActionsInterface(this);
}
@@ -281,30 +240,10 @@
return new GrReportingJsApi(this);
}
- theme(): ThemePluginApi {
- return new GrThemeApi(this);
- }
-
- project(): RepoPluginApi {
- return new GrRepoApi(this);
- }
-
- changeMetadata(): ChangeMetadataPluginApi {
- return new GrChangeMetadataApi(this);
- }
-
admin(): AdminPluginApi {
return new GrAdminApi(this);
}
- settings(): SettingsPluginApi {
- return new GrSettingsApi(this);
- }
-
- styles(): StylesPluginApi {
- return new GrStylesApi(this);
- }
-
restApi(prefix?: string): RestPluginApi {
return new GrPluginRestApi(this, prefix);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
index 205f0fe..595fb4f 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
@@ -18,6 +18,7 @@
import {appContext} from '../../../services/app-context';
import {PluginApi} from '../../../api/plugin';
import {EventDetails, ReportingPluginApi} from '../../../api/reporting';
+import {LifeCycle} from '../../../constants/reporting';
/**
* Defines all methods that will be exported to plugin from reporting service.
@@ -39,9 +40,10 @@
reportLifeCycle(eventName: string, details?: EventDetails) {
this.reporting.trackApi(this.plugin, 'reporting', 'reportLifeCycle');
- this.reporting.reportLifeCycle(
- `${this.plugin.getPluginName()}-${eventName}`,
- details
- );
+ this.reporting.reportLifeCycle(LifeCycle.PLUGIN_LIFE_CYCLE, {
+ ...details,
+ pluginName: this.plugin.getPluginName(),
+ eventName,
+ });
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api_test.js
index 9e3876b..ffc2fbb 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api_test.js
@@ -28,7 +28,6 @@
let plugin;
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
stubRestApi('getAccount').returns(Promise.resolve(null));
});
@@ -63,11 +62,11 @@
assert.isTrue(appContext.reportingService.reportLifeCycle.called);
assert.equal(
appContext.reportingService.reportLifeCycle.lastCall.args[0],
- 'testplugin-test'
+ 'Plugin life cycle'
);
assert.deepEqual(
appContext.reportingService.reportLifeCycle.lastCall.args[1],
- {}
+ {pluginName: 'testplugin', eventName: 'test'}
);
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 60a07a4..db22ce5 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -22,8 +22,6 @@
import '../gr-icons/gr-icons';
import '../gr-label/gr-label';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-label-info_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
@@ -61,9 +59,7 @@
}
@customElement('gr-label-info')
-export class GrLabelInfo extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLabelInfo extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
index c640d23..56ab8c6 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
@@ -43,9 +43,15 @@
}
.positive {
background-color: var(--vote-color-recommended);
+ border-radius: 12px;
+ border: 1px solid var(--vote-outline-recommended);
+ color: var(--chip-color);
}
.negative {
background-color: var(--vote-color-disliked);
+ border-radius: 12px;
+ border: 1px solid var(--vote-outline-disliked);
+ color: var(--chip-color);
}
.hidden {
display: none;
@@ -101,7 +107,10 @@
</gr-label>
</td>
<td>
- <gr-account-link account="[[mappedLabel.account]]"></gr-account-link>
+ <gr-account-link
+ account="[[mappedLabel.account]]"
+ change="[[change]]"
+ ></gr-account-link>
</td>
<td>
<gr-button
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
index b2365aa..e8a38ec 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
@@ -17,8 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-label-info.js';
-import {isHidden} from '../../../test/test-utils.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {isHidden, stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-label-info');
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
index 46b10cc..c13ca6e 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
@@ -21,8 +21,6 @@
* used in gr-label-info.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement} from '@polymer/decorators';
import {htmlTemplate} from './gr-label_html';
@@ -35,9 +33,7 @@
}
@customElement('gr-label')
-export class GrLabel extends TooltipMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrLabel extends TooltipMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
index 4240c77..4be79e2 100644
--- a/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-labeled-autocomplete/gr-labeled-autocomplete.ts
@@ -16,8 +16,6 @@
*/
import '../gr-autocomplete/gr-autocomplete';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-labeled-autocomplete_html';
import {customElement, property} from '@polymer/decorators';
@@ -32,9 +30,7 @@
};
}
@customElement('gr-labeled-autocomplete')
-export class GrLabeledAutocomplete extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLabeledAutocomplete extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
index 4d65874..f76f8d7 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-limited-text_html';
import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
@@ -34,9 +32,7 @@
* and a tooltip containing the full text is enabled.
*/
@customElement('gr-limited-text')
-export class GrLimitedText extends TooltipMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrLimitedText extends TooltipMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
index fa244f6..615eac8 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
@@ -19,8 +19,6 @@
import '../gr-icons/gr-icons';
import '../gr-limited-text/gr-limited-text';
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
import {htmlTemplate} from './gr-linked-chip_html';
@@ -33,9 +31,7 @@
}
@customElement('gr-linked-chip')
-export class GrLinkedChip extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLinkedChip extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_html.ts b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_html.ts
index 8581a0c..cac88b7 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_html.ts
@@ -31,7 +31,10 @@
}
gr-button.remove {
--gr-remove-button-style: {
- border: 0;
+ border-top-width: 0;
+ border-right-width: 0;
+ border-bottom-width: 0;
+ border-left-width: 0;
color: var(--deemphasized-text-color);
font-weight: var(--font-weight-normal);
height: 0.6em;
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
index e2c2d7f..2812b47 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-linked-text_html';
import {GrLinkTextParser, LinkTextParserConfig} from './link-text-parser';
@@ -36,9 +34,7 @@
}
@customElement('gr-linked-text')
-export class GrLinkedText extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrLinkedText extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
index bf532ef..f586f48 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.ts
@@ -18,14 +18,13 @@
import '@polymer/iron-icon/iron-icon';
import '../../../styles/shared-styles';
import '../gr-button/gr-button';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-list-view_html';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {page} from '../../../utils/page-wrapper-utils';
import {property, customElement} from '@polymer/decorators';
import {fireEvent} from '../../../utils/event-util';
+import {debounce, DelayedTask} from '../../../utils/async-util';
const REQUEST_DEBOUNCE_INTERVAL_MS = 200;
@@ -35,12 +34,8 @@
}
}
-const DEBOUNCER_RELOAD = 'reload';
-
@customElement('gr-list-view')
-class GrListView extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrListView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -66,10 +61,12 @@
@property({type: String})
path?: string;
+ private reloadTask?: DelayedTask;
+
/** @override */
- detached() {
- super.detached();
- this.cancelDebouncer(DEBOUNCER_RELOAD);
+ disconnectedCallback() {
+ this.reloadTask?.cancel();
+ super.disconnectedCallback();
}
_filterChanged(newFilter?: string, oldFilter?: string) {
@@ -82,8 +79,8 @@
}
_debounceReload(filter?: string) {
- this.debounce(
- DEBOUNCER_RELOAD,
+ this.reloadTask = debounce(
+ this.reloadTask,
() => {
if (this.path) {
if (filter) {
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
index 20e5296..2c48ec0f 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-overlay_html';
import {IronOverlayMixin} from '../../../mixins/iron-overlay-mixin/iron-overlay-mixin';
@@ -24,6 +22,7 @@
import {IronOverlayBehavior} from '@polymer/iron-overlay-behavior/iron-overlay-behavior';
import {findActiveElement} from '../../../utils/dom-util';
import {fireEvent} from '../../../utils/event-util';
+import {getHovercardContainer} from '../gr-hovercard/gr-hovercard-behavior';
const AWAIT_MAX_ITERS = 10;
const AWAIT_STEP = 5;
@@ -37,7 +36,7 @@
@customElement('gr-overlay')
export class GrOverlay extends IronOverlayMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement)),
+ PolymerElement,
IronOverlayBehavior as IronOverlayBehavior
) {
static get template() {
@@ -79,13 +78,11 @@
// once the type contains the exported member,
// should replace with:
// import {IronFocusablesHelper} from '@polymer/iron-overlay-behavior/iron-focusables-helper';
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- return (window.Polymer as any).IronFocusablesHelper.getTabbableNodes(this);
+ return window.Polymer.IronFocusablesHelper.getTabbableNodes(this);
}
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('iron-overlay-closed', () => this._overlayClosed());
this.addEventListener('iron-overlay-cancelled', () =>
this._overlayClosed()
@@ -122,6 +119,20 @@
}
}
+ _onCaptureFocus(e: Event) {
+ const hovercardContainer = getHovercardContainer();
+ if (hovercardContainer) {
+ // Hovercard container is not a child of an overlay.
+ // When an overlay is opened and a user clicks inside hovercard,
+ // the IronOverlayBehavior doesn't allow to set focus inside a hovercard.
+ // As a result, user can't select a text (username) in the hovercard
+ // in a dialog. We should skip default _onCaptureFocus for hovercards.
+ const path = e.composedPath();
+ if (path.indexOf(hovercardContainer) >= 0) return;
+ }
+ super._onCaptureFocus(e);
+ }
+
/**
* Override the focus stops that iron-overlay-behavior tries to find.
*/
@@ -136,7 +147,7 @@
_awaitOpen(fn: (this: GrOverlay) => void, reject: (error: Error) => void) {
let iters = 0;
const step = () => {
- this.async(() => {
+ setTimeout(() => {
if (this.style.display !== 'none') {
fn.call(this);
} else if (iters++ < AWAIT_MAX_ITERS) {
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
index e009499..9a9dc03 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-page-nav_html';
import {customElement, property} from '@polymer/decorators';
@@ -34,9 +32,7 @@
}
@customElement('gr-page-nav')
-export class GrPageNav extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrPageNav extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -51,14 +47,14 @@
this.bodyScrollHandler = () => this._handleBodyScroll();
}
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
window.addEventListener('scroll', this.bodyScrollHandler);
}
- detached() {
- super.detached();
+ disconnectedCallback() {
window.removeEventListener('scroll', this.bodyScrollHandler);
+ super.disconnectedCallback();
}
_handleBodyScroll() {
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
index 6db1925..31566a8 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
@@ -18,8 +18,6 @@
import '../../../styles/shared-styles';
import '../gr-icons/gr-icons';
import '../gr-labeled-autocomplete/gr-labeled-autocomplete';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-branch-picker_html';
import {singleDecodeURL} from '../../../utils/url-util';
@@ -44,9 +42,7 @@
};
}
@customElement('gr-repo-branch-picker')
-export class GrRepoBranchPicker extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrRepoBranchPicker extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -75,8 +71,8 @@
}
/** @override */
- attached() {
- super.attached();
+ connectedCallback() {
+ super.connectedCallback();
if (this.repo) {
this.$.repoInput.setText(this.repo);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index ec59ddc..ef0367f 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -52,6 +52,7 @@
Base64File,
Base64FileContent,
Base64ImageFile,
+ BasePatchSetNum,
BlameInfo,
BranchInfo,
BranchInput,
@@ -274,7 +275,8 @@
}
@customElement('gr-rest-api-interface')
-export class GrRestApiInterface extends PolymerElement
+export class GrRestApiInterface
+ extends PolymerElement
implements RestApiService {
readonly _cache = siteBasedCache; // Shared across instances.
@@ -610,9 +612,9 @@
};
return this._restApiHelper.send(req).then(response => {
if (response?.ok) {
- return (this.getResponseObject(response) as unknown) as Promise<
- GroupInfo
- >;
+ return (this.getResponseObject(
+ response
+ ) as unknown) as Promise<GroupInfo>;
}
return undefined;
});
@@ -1774,6 +1776,15 @@
}) as Promise<ChangeInfo[] | undefined>;
}
+ getChangesWithSimilarTopic(topic: string): Promise<ChangeInfo[] | undefined> {
+ const query = [`intopic:"${topic}"`].join(' ');
+ return this._restApiHelper.fetchJSON({
+ url: '/changes/',
+ params: {q: query},
+ anonymizedUrl: '/changes/intopic:*',
+ }) as Promise<ChangeInfo[] | undefined>;
+ }
+
getReviewedFiles(
changeNum: NumericChangeId,
patchNum: PatchSetNum
@@ -2220,14 +2231,14 @@
getDiffComments(
changeNum: NumericChangeId,
- basePatchNum: PatchSetNum,
+ basePatchNum: BasePatchSetNum,
patchNum: PatchSetNum,
path: string
): Promise<GetDiffCommentsOutput>;
getDiffComments(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
) {
@@ -2253,14 +2264,14 @@
getDiffRobotComments(
changeNum: NumericChangeId,
- basePatchNum: PatchSetNum,
+ basePatchNum: BasePatchSetNum,
patchNum: PatchSetNum,
path: string
): Promise<GetDiffRobotCommentsOutput>;
getDiffRobotComments(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
) {
@@ -2289,14 +2300,14 @@
getDiffDrafts(
changeNum: NumericChangeId,
- basePatchNum: PatchSetNum,
+ basePatchNum: BasePatchSetNum,
patchNum: PatchSetNum,
path: string
): Promise<GetDiffCommentsOutput>;
getDiffDrafts(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
) {
@@ -2356,7 +2367,7 @@
changeNum: NumericChangeId,
endpoint: '/comments' | '/drafts',
params?: FetchParams,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
): Promise<GetDiffCommentsOutput>;
@@ -2365,7 +2376,7 @@
changeNum: NumericChangeId,
endpoint: '/robotcomments',
params?: FetchParams,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
): Promise<GetDiffRobotCommentsOutput>;
@@ -2374,7 +2385,7 @@
changeNum: NumericChangeId,
endpoint: string,
params?: FetchParams,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
): Promise<
@@ -2820,9 +2831,9 @@
if (!response || (response.status < 200 && response.status >= 300)) {
return Promise.reject(new Error('error'));
}
- return (this.getResponseObject(response) as unknown) as Promise<
- SshKeyInfo
- >;
+ return (this.getResponseObject(
+ response
+ ) as unknown) as Promise<SshKeyInfo>;
})
.then(obj => {
if (!obj || !obj.valid) {
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.js
index 4eef8a2f..3a5a587 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper_test.js
@@ -16,8 +16,7 @@
*/
import '../../../../test/common-test-setup-karma.js';
-import {SiteBasedCache} from './gr-rest-api-helper.js';
-import {FetchPromisesCache, GrRestApiHelper} from './gr-rest-api-helper.js';
+import {SiteBasedCache, FetchPromisesCache, GrRestApiHelper} from './gr-rest-api-helper.js';
import {appContext} from '../../../../services/app-context.js';
suite('gr-rest-api-helper tests', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts b/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
index a2c1253..861381f 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.ts
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {html} from '@polymer/polymer/lib/utils/html-tag';
import {customElement, property, observe} from '@polymer/decorators';
@@ -30,9 +28,7 @@
* GrSelect `gr-select` component.
*/
@customElement('gr-select')
-export class GrSelect extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrSelect extends PolymerElement {
static get template() {
return html` <slot></slot> `;
}
@@ -57,7 +53,7 @@
// Async needed for firefox to populate value. It was trying to do it
// before options from a dom-repeat were rendered previously.
// See https://bugs.chromium.org/p/gerrit/issues/detail?id=7735
- this.async(() => {
+ setTimeout(() => {
// TODO(TS): maybe should check for undefined before assigning
// or fallback to ''
this.nativeSelect.value = this.bindValue!;
@@ -73,9 +69,8 @@
this.nativeSelect.focus();
}
- /** @override */
- created() {
- super.created();
+ constructor() {
+ super();
this.addEventListener('change', () => this._valueChanged());
this.addEventListener('dom-change', () => this._updateValue());
}
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
index 27f4069..a23cb1a 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
@@ -16,8 +16,6 @@
*/
import '../../../styles/shared-styles';
import '../gr-copy-clipboard/gr-copy-clipboard';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-shell-command_html';
import {customElement, property} from '@polymer/decorators';
@@ -29,9 +27,7 @@
}
@customElement('gr-shell-command')
-class GrShellCommand extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+class GrShellCommand extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 885db2a..bf10121 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -21,8 +21,6 @@
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
import '../../../styles/shared-styles';
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-textarea_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -77,13 +75,9 @@
hiddenText: HTMLDivElement;
};
}
-/**
- * @extends PolymerElement
- */
+
@customElement('gr-textarea')
-export class GrTextarea extends KeyboardShortcutMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrTextarea extends KeyboardShortcutMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
@@ -186,7 +180,7 @@
// Put the cursor at the end always.
textarea.selectionStart = textarea.value.length;
textarea.selectionEnd = textarea.selectionStart;
- this.async(() => {
+ setTimeout(() => {
textarea.focus();
});
}
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
index cfd9e81..feed8a6 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../gr-icons/gr-icons';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-tooltip-content_html';
import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
@@ -32,9 +30,7 @@
* Transclude anything inside and wrap them to support tooltip functionality.
*/
@customElement('gr-tooltip-content')
-export class GrTooltipContent extends TooltipMixin(
- GestureEventListeners(LegacyElementMixin(PolymerElement))
-) {
+export class GrTooltipContent extends TooltipMixin(PolymerElement) {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
index c1a8eb2..cab05b4 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
@@ -15,8 +15,6 @@
* limitations under the License.
*/
import '../../../styles/shared-styles';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-tooltip_html';
import {customElement, property, observe} from '@polymer/decorators';
@@ -32,9 +30,7 @@
}
@customElement('gr-tooltip')
-export class GrTooltip extends GestureEventListeners(
- LegacyElementMixin(PolymerElement)
-) {
+export class GrTooltip extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/embed/gr-diff.ts b/polygerrit-ui/app/embed/gr-diff.ts
index 405d22e..cf92ae3 100644
--- a/polygerrit-ui/app/embed/gr-diff.ts
+++ b/polygerrit-ui/app/embed/gr-diff.ts
@@ -21,20 +21,20 @@
// 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 '../api/embed';
import '../scripts/bundled-polymer';
import '../elements/diff/gr-diff/gr-diff';
import '../elements/diff/gr-diff-cursor/gr-diff-cursor';
import {initDiffAppContext} from './gr-diff-app-context-init';
-import {
- GrDiffLine,
- GrDiffLineType,
-} from '../elements/diff/gr-diff/gr-diff-line';
import {GrAnnotation} from '../elements/diff/gr-diff-highlight/gr-annotation';
// Setup appContext for diff.
// TODO (dmfilippov): find a better solution
initDiffAppContext();
// Setup global variables for existing usages of this component
-window.GrDiffLine = GrDiffLine;
-window.GrDiffLineType = GrDiffLineType;
+window.grdiff = {
+ GrAnnotation,
+};
+
+// TODO(oler): Remove when clients have adjusted to namespaced globals above
window.GrAnnotation = GrAnnotation;
diff --git a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts b/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts
index 75ad608..e60c614 100644
--- a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts
+++ b/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts
@@ -88,7 +88,6 @@
/** @override */
disconnectedCallback() {
- super.disconnectedCallback();
// NOTE: if you define your own `detached` in your component
// then this won't take affect (as its not a class yet)
this._handleHideTooltip();
@@ -96,6 +95,7 @@
this.removeEventListener('mouseenter', this.mouseenterHandler);
}
window.removeEventListener('scroll', this.windowScrollHandler);
+ super.disconnectedCallback();
}
@observe('hasTooltip')
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
index ab85b87..1bece26 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -107,6 +107,7 @@
CustomKeyboardEvent,
ShortcutTriggeredEventDetail,
} from '../../types/events';
+import {appContext} from '../../services/app-context';
/** Enum for all special shortcuts */
export enum SPECIAL_SHORTCUT {
@@ -805,6 +806,10 @@
ShortcutSection = ShortcutSection;
+ private _disableKeyboardShortcuts = false;
+
+ private readonly restApiService = appContext.restApiService;
+
modifierPressed(event: CustomKeyboardEvent) {
/* We are checking for g/v as modifiers pressed. There are cases such as
* pressing v and then /, where we want the handler for / to be triggered.
@@ -826,6 +831,7 @@
}
shouldSuppressKeyboardShortcut(event: CustomKeyboardEvent) {
+ if (this._disableKeyboardShortcuts) return true;
const e = getKeyboardEvent(event);
// TODO(TS): maybe override the EventApi, narrow it down to Element always
const target = (dom(e) as EventApi).rootTarget as Element;
@@ -837,8 +843,9 @@
// mark-reviewed and then press ] to go to the next file'.
(tagName === 'INPUT' && type !== 'checkbox') ||
tagName === 'TEXTAREA' ||
- // Suppress shortcuts if the key is 'enter' and target is an anchor.
- (e.keyCode === 13 && tagName === 'A')
+ // Suppress shortcuts if the key is 'enter'
+ // and target is an anchor or button.
+ (e.keyCode === 13 && (tagName === 'A' || tagName === 'BUTTON'))
) {
return true;
}
@@ -926,6 +933,13 @@
/** @override */
connectedCallback() {
super.connectedCallback();
+
+ this.restApiService.getPreferences().then(prefs => {
+ if (prefs?.disable_keyboard_shortcuts) {
+ this._disableKeyboardShortcuts = true;
+ }
+ });
+
const shortcuts = shortcutManager.attachHost(this);
if (!shortcuts) {
return;
@@ -960,10 +974,10 @@
/** @override */
disconnectedCallback() {
- super.disconnectedCallback();
if (shortcutManager.detachHost(this)) {
this.removeOwnKeyBindings();
}
+ super.disconnectedCallback();
}
keyboardShortcuts() {
@@ -1065,14 +1079,13 @@
// This is a workaround
export const KeyboardShortcutMixin = <T extends Constructor<PolymerElement>>(
superClass: T
-): T & Constructor<KeyboardShortcutMixinInterface> => {
- return InternalKeyboardShortcutMixin(
+): T & Constructor<KeyboardShortcutMixinInterface> =>
+ InternalKeyboardShortcutMixin(
// TODO(TS): mixinBehaviors in some lib is returning: `new () => T` instead
// which will fail the type check due to missing IronA11yKeysBehavior interface
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mixinBehaviors([IronA11yKeysBehavior], superClass) as any
);
-};
/** The interface corresponding to KeyboardShortcutMixin */
export interface KeyboardShortcutMixinInterface {
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses.ts b/polygerrit-ui/app/node_modules_licenses/licenses.ts
index f03c7e6..8dcb80e 100644
--- a/polygerrit-ui/app/node_modules_licenses/licenses.ts
+++ b/polygerrit-ui/app/node_modules_licenses/licenses.ts
@@ -57,6 +57,12 @@
sharedLicenseFile: "polymer-2015.txt",
};
+ public static Polymer2016: LicenseInfo = {
+ name: "Polymer-2016",
+ type: LicenseTypes.Bsd3,
+ sharedLicenseFile: "polymer-2016.txt",
+ };
+
public static Polymer2017: LicenseInfo = {
name: "Polymer-2017",
type: LicenseTypes.Bsd3,
@@ -166,6 +172,10 @@
license: SharedLicenses.Polymer2015
},
{
+ name: "@polymer/iron-image",
+ license: SharedLicenses.Polymer2016
+ },
+ {
name: "@polymer/iron-input",
license: SharedLicenses.Polymer2015
},
@@ -206,6 +216,14 @@
license: SharedLicenses.Polymer2015
},
{
+ name: "@polymer/paper-card",
+ license: SharedLicenses.Polymer2015
+ },
+ {
+ name: "@polymer/paper-checkbox",
+ license: SharedLicenses.Polymer2016
+ },
+ {
name: "@polymer/paper-dialog",
license: SharedLicenses.Polymer2015
},
@@ -218,6 +236,10 @@
license: SharedLicenses.Polymer2015
},
{
+ name: "@polymer/paper-dropdown-menu",
+ license: SharedLicenses.Polymer2015
+ },
+ {
name: "@polymer/paper-icon-button",
license: SharedLicenses.Polymer2015
},
@@ -234,6 +256,10 @@
license: SharedLicenses.Polymer2015
},
{
+ name: "@polymer/paper-menu-button",
+ license: SharedLicenses.Polymer2015
+ },
+ {
name: "@polymer/paper-ripple",
license: SharedLicenses.Polymer2014
},
@@ -250,6 +276,10 @@
license: SharedLicenses.Polymer2015
},
{
+ name: "@polymer/paper-tooltip",
+ license: SharedLicenses.Polymer2015
+ },
+ {
name: "@polymer/polymer",
license: SharedLicenses.Polymer2017
},
@@ -345,6 +375,7 @@
type: LicenseTypes.BsdZeroClause,
packageLicenseFile: "LICENSE.txt"
},
+ nonPackages: ["modules", "test/validateModuleExportsMatchCommonJS"],
},
];
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2016.txt b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2016.txt
new file mode 100644
index 0000000..077af5e
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/polymer-2016.txt
@@ -0,0 +1,34 @@
+Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
+
+This code may only be used under the BSD style license found at
+http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
+http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
+found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
+part of the polymer project is also subject to an additional IP rights grant
+found at http://polymer.github.io/PATENTS.txt
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/package.json b/polygerrit-ui/app/package.json
index 5e15990..c943bff 100644
--- a/polygerrit-ui/app/package.json
+++ b/polygerrit-ui/app/package.json
@@ -5,35 +5,40 @@
"dependencies": {
"@polymer/decorators": "^3.0.0",
"@polymer/font-roboto-local": "^3.0.2",
+ "@polymer/iron-a11y-announcer": "^3.1.0",
"@polymer/iron-a11y-keys-behavior": "^3.0.1",
- "@polymer/iron-a11y-announcer": "^3.0.1",
"@polymer/iron-autogrow-textarea": "^3.0.3",
"@polymer/iron-dropdown": "^3.0.1",
- "@polymer/iron-fit-behavior": "^3.0.2",
+ "@polymer/iron-fit-behavior": "^3.1.0",
"@polymer/iron-icon": "^3.0.1",
"@polymer/iron-iconset-svg": "^3.0.1",
"@polymer/iron-input": "^3.0.1",
"@polymer/iron-overlay-behavior": "^3.0.3",
"@polymer/iron-selector": "^3.0.1",
"@polymer/paper-button": "^3.0.1",
+ "@polymer/paper-card": "^3.0.1",
+ "@polymer/paper-checkbox": "^3.1.0",
"@polymer/paper-dialog": "^3.0.1",
"@polymer/paper-dialog-behavior": "^3.0.1",
"@polymer/paper-dialog-scrollable": "^3.0.1",
+ "@polymer/paper-dropdown-menu": "^3.2.0",
"@polymer/paper-input": "^3.2.1",
"@polymer/paper-item": "^3.0.1",
"@polymer/paper-listbox": "^3.0.1",
+ "@polymer/paper-styles": "^3.0.1",
"@polymer/paper-tabs": "^3.1.0",
"@polymer/paper-toggle-button": "^3.0.1",
+ "@polymer/paper-tooltip": "^3.0.1",
"@polymer/polymer": "^3.4.1",
"@types/resize-observer-browser": "^0.1.5",
- "@webcomponents/shadycss": "^1.9.2",
+ "@webcomponents/shadycss": "^1.10.2",
"@webcomponents/webcomponentsjs": "^1.3.3",
"ba-linkify": "file:../../lib/ba-linkify/src/",
"lit-element": "^2.4.0",
- "page": "^1.11.5",
+ "page": "^1.11.6",
"polymer-bridges": "file:../../polymer-bridges/",
"polymer-resin": "^2.0.1",
- "rxjs": "^6.6.2",
+ "rxjs": "^6.6.7",
"shadow-selection-polyfill": "^1.1.0"
},
"license": "Apache-2.0",
diff --git a/polygerrit-ui/app/scripts/bundled-polymer.ts b/polygerrit-ui/app/scripts/bundled-polymer.ts
index a52cc6b..75c99d5 100644
--- a/polygerrit-ui/app/scripts/bundled-polymer.ts
+++ b/polygerrit-ui/app/scripts/bundled-polymer.ts
@@ -26,8 +26,3 @@
// of the polymer.html file.
import './js/bundled-polymer-bridges';
-
-import {importHref} from './import-href';
-
-window.Polymer = window.Polymer || {};
-window.Polymer.importHref = importHref;
diff --git a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
index 85c92d3..66681ee 100644
--- a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
@@ -32,7 +32,6 @@
};
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
provider = new GrEmailSuggestionsProvider(appContext.restApiService);
});
diff --git a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
index 3ce9d9d..1a14abf 100644
--- a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
@@ -33,7 +33,6 @@
};
setup(() => {
- stubRestApi('getConfig').returns(Promise.resolve({}));
provider = new GrGroupSuggestionsProvider(appContext.restApiService);
});
diff --git a/polygerrit-ui/app/scripts/import-href.ts b/polygerrit-ui/app/scripts/import-href.ts
deleted file mode 100644
index 3249c56..0000000
--- a/polygerrit-ui/app/scripts/import-href.ts
+++ /dev/null
@@ -1,119 +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.
- */
-
-// This file is a replacement for the
-// polymer-bridges/polymer/lib/utils/import-href.html file. The html
-// file contains code inside <script>...</script> and can't be imported
-// in es6 modules.
-
-interface ImportHrefElement extends HTMLLinkElement {
- __dynamicImportLoaded?: boolean;
-}
-
-// run a callback when HTMLImports are ready or immediately if
-// this api is not available.
-function whenImportsReady(cb: () => void) {
- const win = window as Window;
- if (win.HTMLImports) {
- win.HTMLImports.whenReady(cb);
- } else {
- cb();
- }
-}
-
-/**
- * Convenience method for importing an HTML document imperatively.
- *
- * This method creates a new `<link rel="import">` element with
- * the provided URL and appends it to the document to start loading.
- * In the `onload` callback, the `import` property of the `link`
- * element will contain the imported document contents.
- *
- * @memberof Polymer
- * @param href URL to document to load.
- * @param onload Callback to notify when an import successfully
- * loaded.
- * @param onerror Callback to notify when an import
- * unsuccessfully loaded.
- * @param async True if the import should be loaded `async`.
- * Defaults to `false`.
- * @return The link element for the URL to be loaded.
- */
-export function importHref(
- href: string,
- onload: (e: Event) => void,
- onerror: (e: Event) => void,
- async = false
-): HTMLLinkElement {
- let link = document.head.querySelector(
- 'link[href="' + href + '"][import-href]'
- ) as ImportHrefElement;
- if (!link) {
- link = document.createElement('link') as ImportHrefElement;
- link.setAttribute('rel', 'import');
- link.setAttribute('href', href);
- link.setAttribute('import-href', '');
- }
- // always ensure link has `async` attribute if user specified one,
- // even if it was previously not async. This is considered less confusing.
- if (async) {
- link.setAttribute('async', '');
- }
- // NOTE: the link may now be in 3 states: (1) pending insertion,
- // (2) inflight, (3) already loaded. In each case, we need to add
- // event listeners to process callbacks.
- const cleanup = function () {
- link.removeEventListener('load', loadListener);
- link.removeEventListener('error', errorListener);
- };
- const loadListener = function (event: Event) {
- cleanup();
- // In case of a successful load, cache the load event on the link so
- // that it can be used to short-circuit this method in the future when
- // it is called with the same href param.
- link.__dynamicImportLoaded = true;
- if (onload) {
- whenImportsReady(() => {
- onload(event);
- });
- }
- };
- const errorListener = function (event: Event) {
- cleanup();
- // In case of an error, remove the link from the document so that it
- // will be automatically created again the next time `importHref` is
- // called.
- if (link.parentNode) {
- link.parentNode.removeChild(link);
- }
- if (onerror) {
- whenImportsReady(() => {
- onerror(event);
- });
- }
- };
- link.addEventListener('load', loadListener);
- link.addEventListener('error', errorListener);
- if (link.parentNode === null) {
- document.head.appendChild(link);
- // if the link already loaded, dispatch a fake load event
- // so that listeners are called and get a proper event argument.
- } else if (link.__dynamicImportLoaded) {
- link.dispatchEvent(new Event('load'));
- }
- return link;
-}
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts
index 0369ccf..dab894e 100644
--- a/polygerrit-ui/app/services/app-context-init.ts
+++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -23,6 +23,8 @@
import {ChangeService} from './change/change-service';
import {ChecksService} from './checks/checks-service';
import {GrJsApiInterface} from '../elements/shared/gr-js-api-interface/gr-js-api-interface-element';
+import {GrStorageService} from './storage/gr-storage_impl';
+import {ConfigService} from './config/config-service';
type ServiceName = keyof AppContext;
type ServiceCreator<T> = () => T;
@@ -73,5 +75,7 @@
changeService: () => new ChangeService(),
checksService: () => new ChecksService(),
jsApiService: () => new GrJsApiInterface(),
+ storageService: () => new GrStorageService(),
+ configService: () => new ConfigService(),
});
}
diff --git a/polygerrit-ui/app/services/app-context.ts b/polygerrit-ui/app/services/app-context.ts
index 1f618fd..fbc3115 100644
--- a/polygerrit-ui/app/services/app-context.ts
+++ b/polygerrit-ui/app/services/app-context.ts
@@ -22,6 +22,8 @@
import {ChangeService} from './change/change-service';
import {ChecksService} from './checks/checks-service';
import {JsApiService} from '../elements/shared/gr-js-api-interface/gr-js-api-types';
+import {StorageService} from './storage/gr-storage';
+import {ConfigService} from './config/config-service';
export interface AppContext {
flagsService: FlagsService;
@@ -32,6 +34,8 @@
changeService: ChangeService;
checksService: ChecksService;
jsApiService: JsApiService;
+ storageService: StorageService;
+ configService: ConfigService;
}
/**
diff --git a/polygerrit-ui/app/services/change/change-model.ts b/polygerrit-ui/app/services/change/change-model.ts
index e7472de..7085d3c 100644
--- a/polygerrit-ui/app/services/change/change-model.ts
+++ b/polygerrit-ui/app/services/change/change-model.ts
@@ -87,6 +87,11 @@
distinctUntilChanged()
);
+export const repo$ = change$.pipe(
+ map(change => change?.project),
+ distinctUntilChanged()
+);
+
export const latestPatchNum$ = change$.pipe(
map(change => computeLatestPatchNum(computeAllPatchSets(change))),
distinctUntilChanged()
@@ -104,8 +109,8 @@
PatchSetNum | undefined
> = changeAndRouterConsistent$.pipe(
withLatestFrom(routerPatchNum$, latestPatchNum$),
- map(([_, routerPatchNum, latestPatchNum]) => {
- return routerPatchNum || latestPatchNum;
- }),
+ map(
+ ([_, routerPatchNum, latestPatchNum]) => routerPatchNum || latestPatchNum
+ ),
distinctUntilChanged()
);
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index 1c5b862..e616bc2 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -19,14 +19,47 @@
import {
Action,
Category,
- CheckResult,
- CheckRun,
+ CheckResult as CheckResultApi,
+ CheckRun as CheckRunApi,
ChecksApiConfig,
LinkIcon,
RunStatus,
} from '../../api/checks';
import {distinctUntilChanged, map} from 'rxjs/operators';
import {PatchSetNumber} from '../../types/common';
+import {AttemptDetail, createAttemptMap} from './checks-util';
+import {assertIsDefined} from '../../utils/common-util';
+
+export interface CheckResult extends CheckResultApi {
+ /**
+ * Internally we want to uniquely identify a run with an id, for example when
+ * efficiently re-rendering lists of runs in the UI.
+ */
+ internalResultId: string;
+}
+
+export interface CheckRun extends CheckRunApi {
+ /**
+ * Internally we want to uniquely identify a result with an id, for example
+ * when efficiently re-rendering lists of results in the UI.
+ */
+ internalRunId: string;
+ /**
+ * Is this run attempt the latest attempt for the check, i.e. does it have
+ * the highest attempt number among all checks with the same name?
+ */
+ isLatestAttempt: boolean;
+ /**
+ * Is this the only attempt for the check, i.e. we don't have data for other
+ * attempts?
+ */
+ isSingleAttempt: boolean;
+ /**
+ * List of all attempts for the same check, ordered by attempt number.
+ */
+ attemptDetails: AttemptDetail[];
+ results?: CheckResult[];
+}
// This is a convenience type for working with results, because when working
// with a bunch of results you will typically also want to know about the run
@@ -73,34 +106,38 @@
);
export const someProvidersAreLoading$ = checksProviderState$.pipe(
- map(state => {
- return Object.values(state).some(providerState => providerState.loading);
- }),
+ map(state =>
+ Object.values(state).some(providerState => providerState.loading)
+ ),
distinctUntilChanged()
);
export const allActions$ = checksProviderState$.pipe(
- map(state => {
- return Object.values(state).reduce(
+ map(state =>
+ Object.values(state).reduce(
(allActions: Action[], providerState: ChecksProviderState) => [
...allActions,
...providerState.actions,
],
[]
- );
- })
+ )
+ )
);
export const allRuns$ = checksProviderState$.pipe(
- map(state => {
- return Object.values(state).reduce(
+ map(state =>
+ Object.values(state).reduce(
(allRuns: CheckRun[], providerState: ChecksProviderState) => [
...allRuns,
...providerState.runs,
],
[]
- );
- })
+ )
+ )
+);
+
+export const allRunsLatest$ = allRuns$.pipe(
+ map(runs => runs.filter(run => run.isLatestAttempt))
);
export const checkToPluginMap$ = checksProviderState$.pipe(
@@ -116,8 +153,8 @@
);
export const allResults$ = checksProviderState$.pipe(
- map(state => {
- return Object.values(state)
+ map(state =>
+ Object.values(state)
.reduce(
(allResults: CheckResult[], providerState: ChecksProviderState) => [
...allResults,
@@ -129,8 +166,8 @@
],
[]
)
- .filter(r => r !== undefined);
- })
+ .filter(r => r !== undefined)
+ )
);
// Must only be used by the checks service or whatever is in control of this
@@ -151,14 +188,20 @@
privateState$.next(nextState);
}
-// TODO(brohlfs): Remove all fake runs by end of January. They are just making
+// TODO(brohlfs): Remove all fake runs by end of April. They are just making
// it easier to develop the UI and always see all the different types/states of
// runs and results.
export const fakeRun0: CheckRun = {
+ internalRunId: 'f0',
checkName: 'FAKE Error Finder',
+ labelName: 'Presubmit',
+ isSingleAttempt: true,
+ isLatestAttempt: true,
+ attemptDetails: [],
results: [
{
+ internalResultId: 'f0r0',
category: Category.ERROR,
summary: 'I would like to point out this error: 1 is not equal to 2!',
links: [
@@ -167,10 +210,36 @@
tags: [{name: 'OBSOLETE'}, {name: 'E2E'}],
},
{
+ internalResultId: 'f0r1',
category: Category.ERROR,
summary: 'Running the mighty test has failed by crashing.',
+ actions: [
+ {
+ name: 'Ignore',
+ tooltip: 'Ignore this result',
+ primary: true,
+ callback: () => undefined,
+ },
+ {
+ name: 'Flag',
+ tooltip: 'Flag this result as not useful',
+ primary: true,
+ callback: () => undefined,
+ },
+ {
+ name: 'Upload',
+ tooltip: 'Upload the result to the super cloud.',
+ primary: false,
+ callback: () => undefined,
+ },
+ ],
+ tags: [{name: 'INTERRUPTED'}, {name: 'WINDOWS'}],
links: [
- {primary: true, url: 'https://www.google.com', icon: LinkIcon.EXTERNAL},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.EXTERNAL},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.DOWNLOAD},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.REPORT_BUG},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.HELP_PAGE},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.HISTORY},
],
},
],
@@ -178,27 +247,53 @@
};
export const fakeRun1: CheckRun = {
+ internalRunId: 'f1',
checkName: 'FAKE Super Check',
labelName: 'Verified',
+ isSingleAttempt: true,
+ isLatestAttempt: true,
+ attemptDetails: [],
results: [
{
+ internalResultId: 'f1r0',
category: Category.WARNING,
summary: 'We think that you could improve this.',
message: `There is a lot to be said. A lot. I say, a lot.\n
So please keep reading.`,
tags: [{name: 'INTERRUPTED'}, {name: 'WINDOWS'}],
+ links: [
+ {primary: true, url: 'https://google.com', icon: LinkIcon.EXTERNAL},
+ {primary: true, url: 'https://google.com', icon: LinkIcon.DOWNLOAD},
+ {
+ primary: true,
+ url: 'https://google.com',
+ icon: LinkIcon.DOWNLOAD_MOBILE,
+ },
+ {primary: true, url: 'https://google.com', icon: LinkIcon.IMAGE},
+ ],
},
],
status: RunStatus.RUNNING,
};
export const fakeRun2: CheckRun = {
+ internalRunId: 'f2',
checkName: 'FAKE Mega Analysis',
+ isSingleAttempt: true,
+ isLatestAttempt: true,
+ attemptDetails: [],
results: [
{
+ internalResultId: 'f2r0',
category: Category.INFO,
summary: 'This is looking a bit too large.',
- message: 'We are still looking into how large exactly. Stay tuned.',
+ message: `We are still looking into how large exactly. Stay tuned.
+And have a look at https://www.google.com!
+
+Or have a look at change 30000.
+Example code:
+ const constable = '';
+ var variable = '';`,
tags: [{name: 'FLAKY'}, {name: 'MAC-OS'}],
},
],
@@ -206,15 +301,105 @@
};
export const fakeRun3: CheckRun = {
+ internalRunId: 'f3',
checkName: 'FAKE Critical Observations',
status: RunStatus.RUNNABLE,
+ isSingleAttempt: true,
+ isLatestAttempt: true,
+ attemptDetails: [],
};
-export const fakeRun4: CheckRun = {
- checkName: 'FAKE TODO Elimination',
+export const fakeRun4_1: CheckRun = {
+ internalRunId: 'f4',
+ checkName: 'FAKE Elimination',
status: RunStatus.COMPLETED,
+ attempt: 1,
+ isSingleAttempt: false,
+ isLatestAttempt: false,
+ attemptDetails: [],
};
+export const fakeRun4_2: CheckRun = {
+ internalRunId: 'f4',
+ checkName: 'FAKE Elimination',
+ status: RunStatus.COMPLETED,
+ attempt: 2,
+ isSingleAttempt: false,
+ isLatestAttempt: false,
+ attemptDetails: [],
+ results: [
+ {
+ internalResultId: 'f42r0',
+ category: Category.INFO,
+ summary: 'Please eliminate all the TODOs!',
+ },
+ ],
+};
+
+export const fakeRun4_3: CheckRun = {
+ internalRunId: 'f4',
+ checkName: 'FAKE Elimination',
+ status: RunStatus.COMPLETED,
+ attempt: 3,
+ isSingleAttempt: false,
+ isLatestAttempt: false,
+ attemptDetails: [],
+ results: [
+ {
+ internalResultId: 'f43r0',
+ category: Category.ERROR,
+ summary: 'Without eliminating all the TODOs your change will break!',
+ },
+ ],
+};
+
+export const fakeRun4_4: CheckRun = {
+ internalRunId: 'f4',
+ checkName: 'FAKE Elimination',
+ status: RunStatus.RUNNING,
+ attempt: 4,
+ isSingleAttempt: false,
+ isLatestAttempt: true,
+ attemptDetails: [],
+ results: [
+ {
+ internalResultId: 'f44r0',
+ category: Category.INFO,
+ summary: 'Dont be afraid. All TODOs will be eliminated.',
+ },
+ ],
+};
+
+export const fakeActions: Action[] = [
+ {
+ name: 'Fake Action 1',
+ primary: false,
+ tooltip: 'Tooltip for Fake Action 1',
+ callback: () => {
+ console.warn('fake action 1 triggered');
+ return undefined;
+ },
+ },
+ {
+ name: 'Fake Action 2',
+ primary: false,
+ tooltip: 'Tooltip for Fake Action 2',
+ callback: () => {
+ console.warn('fake action 2 triggered');
+ return undefined;
+ },
+ },
+ {
+ name: 'Fake Action 3',
+ primary: false,
+ tooltip: 'Tooltip for Fake Action 3',
+ callback: () => {
+ console.warn('fake action 3 triggered');
+ return undefined;
+ },
+ },
+];
+
export function updateStateSetLoading(pluginName: string) {
const nextState = {...privateState$.getValue()};
nextState.providerNameToState = {...nextState.providerNameToState};
@@ -227,15 +412,38 @@
export function updateStateSetResults(
pluginName: string,
- runs: CheckRun[],
+ runs: CheckRunApi[],
actions: Action[] = []
) {
+ const attemptMap = createAttemptMap(runs);
+ for (const attemptInfo of attemptMap.values()) {
+ // Per run only one attempt can be undefined, so the '?? -1' is not really
+ // relevant for sorting.
+ attemptInfo.attempts.sort((a, b) => (b.attempt ?? -1) - (a.attempt ?? -1));
+ }
const nextState = {...privateState$.getValue()};
nextState.providerNameToState = {...nextState.providerNameToState};
nextState.providerNameToState[pluginName] = {
...nextState.providerNameToState[pluginName],
loading: false,
- runs: [...runs],
+ runs: runs.map(run => {
+ const runId = `${run.checkName}-${run.change}-${run.patchset}-${run.attempt}`;
+ const attemptInfo = attemptMap.get(run.checkName);
+ assertIsDefined(attemptInfo, 'attemptInfo');
+ return {
+ ...run,
+ internalRunId: runId,
+ isLatestAttempt: attemptInfo.latestAttempt === run.attempt,
+ isSingleAttempt: attemptInfo.isSingleAttempt,
+ attemptDetails: attemptInfo.attempts,
+ results: (run.results ?? []).map((result, i) => {
+ return {
+ ...result,
+ internalResultId: `${runId}-${i}`,
+ };
+ }),
+ };
+ }),
actions: [...actions],
};
privateState$.next(nextState);
diff --git a/polygerrit-ui/app/services/checks/checks-service.ts b/polygerrit-ui/app/services/checks/checks-service.ts
index fd1f810..18d53612 100644
--- a/polygerrit-ui/app/services/checks/checks-service.ts
+++ b/polygerrit-ui/app/services/checks/checks-service.ts
@@ -48,6 +48,9 @@
timer,
} from 'rxjs';
import {PatchSetNumber} from '../../types/common';
+import {getCurrentRevision} from '../../utils/change-util';
+import {getShaByPatchNum} from '../../utils/patch-set-util';
+import {assertIsDefined} from '../../utils/common-util';
export class ChecksService {
private readonly providers: {[name: string]: ChecksProvider} = {};
@@ -126,10 +129,23 @@
runs: [],
});
}
+ assertIsDefined(change.revisions, 'change.revisions');
+ const patchsetSha = getShaByPatchNum(change.revisions, patchNum);
+ // Sometimes patchNum is updated earlier than change, so change
+ // revisions don't have patchNum yet
+ if (!patchsetSha) {
+ return of({
+ responseCode: ResponseCode.OK,
+ runs: [],
+ });
+ }
const data: ChangeData = {
changeNumber: changeNum,
patchsetNumber: patchNum,
+ patchsetSha,
repo: change.project,
+ commmitMessage: getCurrentRevision(change)?.commit?.message,
+ changeInfo: change,
};
updateStateSetLoading(pluginName);
return from(this.providers[pluginName].fetch(data));
diff --git a/polygerrit-ui/app/services/checks/checks-util.ts b/polygerrit-ui/app/services/checks/checks-util.ts
index ea532ea..339d0bf 100644
--- a/polygerrit-ui/app/services/checks/checks-util.ts
+++ b/polygerrit-ui/app/services/checks/checks-util.ts
@@ -14,8 +14,58 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Action, Category, CheckRun, RunStatus} from '../../api/checks';
+import {
+ Action,
+ Category,
+ CheckRun as CheckRunApi,
+ CheckResult as CheckResultApi,
+ LinkIcon,
+ RunStatus,
+} from '../../api/checks';
import {assertNever} from '../../utils/common-util';
+import {CheckResult, CheckRun} from './checks-model';
+
+export function iconForLink(linkIcon: LinkIcon) {
+ switch (linkIcon) {
+ case LinkIcon.EXTERNAL:
+ return 'launch';
+ case LinkIcon.IMAGE:
+ return 'insert-photo';
+ case LinkIcon.HISTORY:
+ return 'restore';
+ case LinkIcon.DOWNLOAD:
+ return 'download';
+ case LinkIcon.DOWNLOAD_MOBILE:
+ return 'system-update';
+ case LinkIcon.HELP_PAGE:
+ return 'help-outline';
+ case LinkIcon.REPORT_BUG:
+ return 'bug';
+ default:
+ assertNever(linkIcon, `Unsupported LinkIcon: ${linkIcon}`);
+ }
+}
+
+export function tooltipForLink(linkIcon: LinkIcon) {
+ switch (linkIcon) {
+ case LinkIcon.EXTERNAL:
+ return 'Link to details';
+ case LinkIcon.IMAGE:
+ return 'Link to image';
+ case LinkIcon.HISTORY:
+ return 'Link to result history';
+ case LinkIcon.DOWNLOAD:
+ return 'Download';
+ case LinkIcon.DOWNLOAD_MOBILE:
+ return 'Download';
+ case LinkIcon.HELP_PAGE:
+ return 'Link to help page';
+ case LinkIcon.REPORT_BUG:
+ return 'Link for reporting a problem';
+ default:
+ assertNever(linkIcon, `Unsupported LinkIcon: ${linkIcon}`);
+ }
+}
export function worstCategory(run: CheckRun) {
if (hasResultsOf(run, Category.ERROR)) return Category.ERROR;
@@ -118,6 +168,20 @@
return hasCompleted(run) && hasResultsOf(run, category);
}
+export function hasResults(run: CheckRun): boolean {
+ return (run.results ?? []).length > 0;
+}
+
+export function allResults(runs: CheckRun[]): CheckResult[] {
+ return runs.reduce(
+ (results: CheckResult[], run: CheckRun) => [
+ ...results,
+ ...(run.results ?? []),
+ ],
+ []
+ );
+}
+
export function hasResultsOf(run: CheckRun, category: Category) {
return getResultsOf(run, category).length > 0;
}
@@ -168,3 +232,63 @@
})
);
}
+
+export interface AttemptDetail {
+ attempt: number | undefined;
+ icon: string;
+}
+
+export interface AttemptInfo {
+ latestAttempt: number | undefined;
+ isSingleAttempt: boolean;
+ attempts: AttemptDetail[];
+}
+
+export function createAttemptMap(runs: CheckRunApi[]) {
+ const map = new Map<string, AttemptInfo>();
+ for (const run of runs) {
+ const value = map.get(run.checkName);
+ const detail = {
+ attempt: run.attempt,
+ icon: iconForRun(fromApiToInternalRun(run)),
+ };
+ if (value === undefined) {
+ map.set(run.checkName, {
+ latestAttempt: run.attempt,
+ isSingleAttempt: true,
+ attempts: [detail],
+ });
+ continue;
+ }
+ if (!run.attempt || !value.latestAttempt) {
+ throw new Error(
+ 'If multiple run attempts are provided, ' +
+ 'then each run must have the "attempt" property set.'
+ );
+ }
+ value.isSingleAttempt = false;
+ if (run.attempt > value.latestAttempt) {
+ value.latestAttempt = run.attempt;
+ }
+ value.attempts.push(detail);
+ }
+ return map;
+}
+
+export function fromApiToInternalRun(run: CheckRunApi): CheckRun {
+ return {
+ ...run,
+ internalRunId: 'fake',
+ isSingleAttempt: false,
+ isLatestAttempt: false,
+ attemptDetails: [],
+ results: (run.results ?? []).map(fromApiToInternalResult),
+ };
+}
+
+export function fromApiToInternalResult(result: CheckResultApi): CheckResult {
+ return {
+ ...result,
+ internalResultId: 'fake',
+ };
+}
diff --git a/polygerrit-ui/app/services/config/config-model.ts b/polygerrit-ui/app/services/config/config-model.ts
new file mode 100644
index 0000000..254760b
--- /dev/null
+++ b/polygerrit-ui/app/services/config/config-model.ts
@@ -0,0 +1,44 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {ConfigInfo} from '../../types/common';
+import {BehaviorSubject, Observable} from 'rxjs';
+import {map, distinctUntilChanged} from 'rxjs/operators';
+
+interface ConfigState {
+ repoConfig?: ConfigInfo;
+}
+
+// TODO: Figure out how to best enforce immutability of all states. Use Immer?
+// Use DeepReadOnly?
+const initialState: ConfigState = {};
+
+const privateState$ = new BehaviorSubject(initialState);
+
+// Re-exporting as Observable so that you can only subscribe, but not emit.
+export const configState$: Observable<ConfigState> = privateState$;
+
+// Must only be used by the change service or whatever is in control of this
+// model.
+export function updateRepoConfig(repoConfig?: ConfigInfo) {
+ const current = privateState$.getValue();
+ privateState$.next({...current, repoConfig});
+}
+
+export const repoConfig$ = configState$.pipe(
+ map(configState => configState.repoConfig),
+ distinctUntilChanged()
+);
diff --git a/polygerrit-ui/app/services/config/config-service.ts b/polygerrit-ui/app/services/config/config-service.ts
new file mode 100644
index 0000000..d6ff99c
--- /dev/null
+++ b/polygerrit-ui/app/services/config/config-service.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {updateRepoConfig} from './config-model';
+import {repo$} from '../change/change-model';
+import {appContext} from '../app-context';
+import {switchMap} from 'rxjs/operators';
+import {ConfigInfo, RepoName} from '../../types/common';
+import {from, of} from 'rxjs';
+
+export class ConfigService {
+ private readonly restApiService = appContext.restApiService;
+
+ constructor() {
+ repo$
+ .pipe(
+ switchMap((repo?: RepoName) => {
+ if (repo === undefined) return of(undefined);
+ return from(this.restApiService.getProjectConfig(repo));
+ })
+ )
+ .subscribe((repoConfig?: ConfigInfo) => {
+ updateRepoConfig(repoConfig);
+ });
+ }
+}
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index 878b8f7..ff950b8 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -29,7 +29,6 @@
// with the new Checks plugin API.
CI_REBOOT_CHECKS = 'UiFeature__ci_reboot_checks',
NEW_CHANGE_SUMMARY_UI = 'UiFeature__new_change_summary_ui',
- PORTING_COMMENTS = 'UiFeature__porting_comments',
NEW_IMAGE_DIFF_UI = 'UiFeature__new_image_diff_ui',
COMMENT_CONTEXT = 'UiFeature__comment_context',
}
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
index 1be1d63..d7081ce 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
@@ -18,6 +18,7 @@
import {NumericChangeId} from '../../types/common';
import {EventDetails} from '../../api/reporting';
import {PluginApi} from '../../api/plugin';
+import {Execution, LifeCycle, Timing} from '../../constants/reporting';
export type EventValue = string | number | {error?: Error};
@@ -55,11 +56,11 @@
/**
* Reset named timer.
*/
- time(name: string): void;
+ time(name: Timing): void;
/**
* Finish named timer and report it to server.
*/
- timeEnd(name: string, eventDetails?: EventDetails): void;
+ timeEnd(name: Timing, eventDetails?: EventDetails): void;
/**
* Reports just line timeEnd, but additionally reports an average given a
* denominator and a separate reporting name for the average.
@@ -70,8 +71,8 @@
* compute the average.
*/
timeEndWithAverage(
- name: string,
- averageName: string,
+ name: Timing,
+ averageName: Timing,
denominator: number
): void;
/**
@@ -87,18 +88,22 @@
* @param elapsed The time elapsed of the RPC.
*/
reportRpcTiming(anonymizedUrl: string, elapsed: number): void;
- reportLifeCycle(eventName: string, details?: EventDetails): void;
+ reportLifeCycle(eventName: LifeCycle, details?: EventDetails): void;
/**
* Use this method, if you want to check/count how often a certain code path
* is executed. For example you can use this method to prove that certain code
* paths are dead: Add reportExecution(), check the logs a week later, then
- * safely remove the coe.
+ * safely remove the code.
*
* Every execution is only reported once per session.
*/
- reportExecution(id: string, details: EventDetails): void;
- trackApi(plugin: PluginApi, object: string, method: string): void;
+ reportExecution(id: Execution, details?: EventDetails): void;
+ trackApi(
+ plugin: Pick<PluginApi, 'getPluginName'>,
+ object: string,
+ method: string
+ ): void;
reportInteraction(eventName: string, details?: EventDetails): void;
/**
* A draft interaction was started. Update the time-between-draft-actions
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
index e57670d..5fd4234 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -21,6 +21,7 @@
import {NumericChangeId} from '../../types/common';
import {EventDetails} from '../../api/reporting';
import {PluginApi} from '../../api/plugin';
+import {Execution, LifeCycle, Timing} from '../../constants/reporting';
// Latency reporting constants.
@@ -30,9 +31,6 @@
UI_LATENCY: 'UI Latency',
RPC: 'RPC Timing',
},
- EVENT: {
- APP_STARTED: 'App Started',
- },
};
const LIFECYCLE = {
@@ -72,39 +70,19 @@
},
};
-const TIMER = {
- CHANGE_DISPLAYED: 'ChangeDisplayed',
- CHANGE_LOAD_FULL: 'ChangeFullyLoaded',
- DASHBOARD_DISPLAYED: 'DashboardDisplayed',
- DIFF_VIEW_CONTENT_DISPLAYED: 'DiffViewOnlyContent',
- DIFF_VIEW_DISPLAYED: 'DiffViewDisplayed',
- DIFF_VIEW_LOAD_FULL: 'DiffViewFullyLoaded',
- FILE_LIST_DISPLAYED: 'FileListDisplayed',
- PLUGINS_LOADED: 'PluginsLoaded',
- STARTUP_CHANGE_DISPLAYED: 'StartupChangeDisplayed',
- STARTUP_CHANGE_LOAD_FULL: 'StartupChangeFullyLoaded',
- STARTUP_DASHBOARD_DISPLAYED: 'StartupDashboardDisplayed',
- STARTUP_DIFF_VIEW_CONTENT_DISPLAYED: 'StartupDiffViewOnlyContent',
- STARTUP_DIFF_VIEW_DISPLAYED: 'StartupDiffViewDisplayed',
- STARTUP_DIFF_VIEW_LOAD_FULL: 'StartupDiffViewFullyLoaded',
- STARTUP_FILE_LIST_DISPLAYED: 'StartupFileListDisplayed',
- WEB_COMPONENTS_READY: 'WebComponentsReady',
- METRICS_PLUGIN_LOADED: 'MetricsPluginLoaded',
-};
-
-const STARTUP_TIMERS = {
- [TIMER.PLUGINS_LOADED]: 0,
- [TIMER.METRICS_PLUGIN_LOADED]: 0,
- [TIMER.STARTUP_CHANGE_DISPLAYED]: 0,
- [TIMER.STARTUP_CHANGE_LOAD_FULL]: 0,
- [TIMER.STARTUP_DASHBOARD_DISPLAYED]: 0,
- [TIMER.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED]: 0,
- [TIMER.STARTUP_DIFF_VIEW_DISPLAYED]: 0,
- [TIMER.STARTUP_DIFF_VIEW_LOAD_FULL]: 0,
- [TIMER.STARTUP_FILE_LIST_DISPLAYED]: 0,
- [TIMING.EVENT.APP_STARTED]: 0,
+const STARTUP_TIMERS: {[name: string]: number} = {
+ [Timing.PLUGINS_LOADED]: 0,
+ [Timing.METRICS_PLUGIN_LOADED]: 0,
+ [Timing.STARTUP_CHANGE_DISPLAYED]: 0,
+ [Timing.STARTUP_CHANGE_LOAD_FULL]: 0,
+ [Timing.STARTUP_DASHBOARD_DISPLAYED]: 0,
+ [Timing.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED]: 0,
+ [Timing.STARTUP_DIFF_VIEW_DISPLAYED]: 0,
+ [Timing.STARTUP_DIFF_VIEW_LOAD_FULL]: 0,
+ [Timing.STARTUP_FILE_LIST_DISPLAYED]: 0,
+ [Timing.APP_STARTED]: 0,
// WebComponentsReady timer is triggered from gr-router.
- [TIMER.WEB_COMPONENTS_READY]: 0,
+ [Timing.WEB_COMPONENTS_READY]: 0,
};
const DRAFT_ACTION_TIMER = 'TimeBetweenDraftActions';
@@ -163,9 +141,7 @@
lineno?: number,
colno?: number,
error?: Error
- ) => {
- return onError(oldOnError, event, source, lineno, colno, error);
- };
+ ) => onError(oldOnError, event, source, lineno, colno, error);
context.addEventListener(
'unhandledrejection',
(e: PromiseRejectionEvent) => {
@@ -327,7 +303,7 @@
private _arePluginsLoaded() {
return (
- this._baselines && !hasOwnProperty(this._baselines, TIMER.PLUGINS_LOADED)
+ this._baselines && !hasOwnProperty(this._baselines, Timing.PLUGINS_LOADED)
);
}
@@ -335,7 +311,7 @@
return (
this._arePluginsLoaded() ||
(this._baselines &&
- !hasOwnProperty(this._baselines, TIMER.METRICS_PLUGIN_LOADED))
+ !hasOwnProperty(this._baselines, Timing.METRICS_PLUGIN_LOADED))
);
}
@@ -443,23 +419,29 @@
* User-perceived app start time, should be reported when the app is ready.
*/
appStarted() {
- this.timeEnd(TIMING.EVENT.APP_STARTED);
+ this.timeEnd(Timing.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
- );
+ let eventName;
+ if (document.visibilityState === 'hidden') {
+ eventName = LifeCycle.VISIBILILITY_HIDDEN;
+ } else if (document.visibilityState === 'visible') {
+ eventName = LifeCycle.VISIBILILITY_VISIBLE;
+ }
+ if (eventName)
+ this.reporter(
+ LIFECYCLE.TYPE,
+ LIFECYCLE.CATEGORY.VISIBILITY,
+ eventName,
+ undefined,
+ {
+ hiddenDurationMs: this.hiddenDurationTimer.hiddenDurationMs,
+ },
+ false
+ );
}
/**
@@ -495,13 +477,13 @@
for (const prop of Object.keys(this._baselines)) {
delete this._baselines[prop];
}
- this.time(TIMER.CHANGE_DISPLAYED);
- this.time(TIMER.CHANGE_LOAD_FULL);
- this.time(TIMER.DASHBOARD_DISPLAYED);
- this.time(TIMER.DIFF_VIEW_CONTENT_DISPLAYED);
- this.time(TIMER.DIFF_VIEW_DISPLAYED);
- this.time(TIMER.DIFF_VIEW_LOAD_FULL);
- this.time(TIMER.FILE_LIST_DISPLAYED);
+ this.time(Timing.CHANGE_DISPLAYED);
+ this.time(Timing.CHANGE_LOAD_FULL);
+ this.time(Timing.DASHBOARD_DISPLAYED);
+ this.time(Timing.DIFF_VIEW_CONTENT_DISPLAYED);
+ this.time(Timing.DIFF_VIEW_DISPLAYED);
+ this.time(Timing.DIFF_VIEW_LOAD_FULL);
+ this.time(Timing.FILE_LIST_DISPLAYED);
this.reportRepoName = undefined;
this.reportChangeId = undefined;
// reset slow rpc list since here start page loads which report these rpcs
@@ -519,60 +501,63 @@
}
dashboardDisplayed() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_DASHBOARD_DISPLAYED)) {
- this.timeEnd(TIMER.STARTUP_DASHBOARD_DISPLAYED, this._pageLoadDetails());
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_DASHBOARD_DISPLAYED)) {
+ this.timeEnd(Timing.STARTUP_DASHBOARD_DISPLAYED, this._pageLoadDetails());
} else {
- this.timeEnd(TIMER.DASHBOARD_DISPLAYED, this._pageLoadDetails());
+ this.timeEnd(Timing.DASHBOARD_DISPLAYED, this._pageLoadDetails());
}
}
changeDisplayed() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_CHANGE_DISPLAYED)) {
- this.timeEnd(TIMER.STARTUP_CHANGE_DISPLAYED, this._pageLoadDetails());
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_CHANGE_DISPLAYED)) {
+ this.timeEnd(Timing.STARTUP_CHANGE_DISPLAYED, this._pageLoadDetails());
} else {
- this.timeEnd(TIMER.CHANGE_DISPLAYED, this._pageLoadDetails());
+ this.timeEnd(Timing.CHANGE_DISPLAYED, this._pageLoadDetails());
}
}
changeFullyLoaded() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_CHANGE_LOAD_FULL)) {
- this.timeEnd(TIMER.STARTUP_CHANGE_LOAD_FULL);
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_CHANGE_LOAD_FULL)) {
+ this.timeEnd(Timing.STARTUP_CHANGE_LOAD_FULL);
} else {
- this.timeEnd(TIMER.CHANGE_LOAD_FULL);
+ this.timeEnd(Timing.CHANGE_LOAD_FULL);
}
}
diffViewDisplayed() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_DIFF_VIEW_DISPLAYED)) {
- this.timeEnd(TIMER.STARTUP_DIFF_VIEW_DISPLAYED, this._pageLoadDetails());
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_DIFF_VIEW_DISPLAYED)) {
+ this.timeEnd(Timing.STARTUP_DIFF_VIEW_DISPLAYED, this._pageLoadDetails());
} else {
- this.timeEnd(TIMER.DIFF_VIEW_DISPLAYED, this._pageLoadDetails());
+ this.timeEnd(Timing.DIFF_VIEW_DISPLAYED, this._pageLoadDetails());
}
}
diffViewFullyLoaded() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_DIFF_VIEW_LOAD_FULL)) {
- this.timeEnd(TIMER.STARTUP_DIFF_VIEW_LOAD_FULL);
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_DIFF_VIEW_LOAD_FULL)) {
+ this.timeEnd(Timing.STARTUP_DIFF_VIEW_LOAD_FULL);
} else {
- this.timeEnd(TIMER.DIFF_VIEW_LOAD_FULL);
+ this.timeEnd(Timing.DIFF_VIEW_LOAD_FULL);
}
}
diffViewContentDisplayed() {
if (
- hasOwnProperty(this._baselines, TIMER.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED)
+ hasOwnProperty(
+ this._baselines,
+ Timing.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED
+ )
) {
- this.timeEnd(TIMER.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED);
+ this.timeEnd(Timing.STARTUP_DIFF_VIEW_CONTENT_DISPLAYED);
} else {
- this.timeEnd(TIMER.DIFF_VIEW_CONTENT_DISPLAYED);
+ this.timeEnd(Timing.DIFF_VIEW_CONTENT_DISPLAYED);
}
}
fileListDisplayed() {
- if (hasOwnProperty(this._baselines, TIMER.STARTUP_FILE_LIST_DISPLAYED)) {
- this.timeEnd(TIMER.STARTUP_FILE_LIST_DISPLAYED);
+ if (hasOwnProperty(this._baselines, Timing.STARTUP_FILE_LIST_DISPLAYED)) {
+ this.timeEnd(Timing.STARTUP_FILE_LIST_DISPLAYED);
} else {
- this.timeEnd(TIMER.FILE_LIST_DISPLAYED);
+ this.timeEnd(Timing.FILE_LIST_DISPLAYED);
}
}
@@ -607,21 +592,27 @@
}
reportExtension(name: string) {
- this.reporter(LIFECYCLE.TYPE, LIFECYCLE.CATEGORY.EXTENSION_DETECTED, name);
+ this.reporter(
+ LIFECYCLE.TYPE,
+ LIFECYCLE.CATEGORY.EXTENSION_DETECTED,
+ LifeCycle.EXTENSION_DETECTED,
+ undefined,
+ {name}
+ );
}
pluginLoaded(name: string) {
if (name.startsWith('metrics-')) {
- this.timeEnd(TIMER.METRICS_PLUGIN_LOADED);
+ this.timeEnd(Timing.METRICS_PLUGIN_LOADED);
}
}
pluginsLoaded(pluginsList?: string[]) {
- this.timeEnd(TIMER.PLUGINS_LOADED);
+ this.timeEnd(Timing.PLUGINS_LOADED);
this.reporter(
LIFECYCLE.TYPE,
LIFECYCLE.CATEGORY.PLUGINS_INSTALLED,
- LIFECYCLE.CATEGORY.PLUGINS_INSTALLED,
+ LifeCycle.PLUGINS_INSTALLED,
undefined,
{pluginsList: pluginsList || []},
true
@@ -629,9 +620,9 @@
}
/**
- * Reset named timer.
+ * Reset named Timing.
*/
- time(name: string) {
+ time(name: Timing) {
this._baselines[name] = now();
window.performance.mark(`${name}-start`);
}
@@ -639,7 +630,7 @@
/**
* Finish named timer and report it to server.
*/
- timeEnd(name: string, eventDetails?: EventDetails) {
+ timeEnd(name: Timing, eventDetails?: EventDetails) {
if (!hasOwnProperty(this._baselines, name)) {
return;
}
@@ -667,7 +658,7 @@
* @param denominator Number by which to divide the total to
* compute the average.
*/
- timeEndWithAverage(name: string, averageName: string, denominator: number) {
+ timeEndWithAverage(name: Timing, averageName: Timing, denominator: number) {
if (!hasOwnProperty(this._baselines, name)) {
return;
}
@@ -770,7 +761,7 @@
}
}
- reportLifeCycle(eventName: string, details: EventDetails) {
+ reportLifeCycle(eventName: LifeCycle, details: EventDetails) {
this.reporter(
LIFECYCLE.TYPE,
LIFECYCLE.CATEGORY.DEFAULT,
@@ -792,30 +783,32 @@
);
}
- reportExecution(id: string, details: EventDetails) {
+ reportExecution(name: Execution, details?: EventDetails) {
+ const id = `${name}${JSON.stringify(details)}`;
if (this.executionReported.has(id)) return;
this.executionReported.add(id);
this.reporter(
LIFECYCLE.TYPE,
LIFECYCLE.CATEGORY.EXECUTION,
- id,
+ name,
undefined,
details,
true // skip console log
);
}
- trackApi(plugin: PluginApi, object: string, method: string) {
- this.reportExecution('plugin-api', {
- plugin: plugin.getPluginName(),
- object,
- method,
- });
+ trackApi(
+ pluginApi: Pick<PluginApi, 'getPluginName'>,
+ object: string,
+ method: string
+ ) {
+ const plugin = pluginApi?.getPluginName() ?? 'unknown';
+ this.reportExecution(Execution.PLUGIN_API, {plugin, object, method});
}
/**
* A draft interaction was started. Update the time-between-draft-actions
- * timer.
+ * Timing.
*/
recordDraftInteraction() {
// If there is no timer defined, then this is the first interaction.
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
index 7d66484..c180439 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -17,6 +17,7 @@
import {ReportingService, Timer} from './gr-reporting';
import {EventDetails} from '../../api/reporting';
import {PluginApi} from '../../api/plugin';
+import {Execution} from '../../constants/reporting';
export class MockTimer implements Timer {
end(): this {
@@ -46,9 +47,7 @@
diffViewDisplayed: () => {},
diffViewFullyLoaded: () => {},
fileListDisplayed: () => {},
- getTimer: () => {
- return new MockTimer();
- },
+ getTimer: () => new MockTimer(),
locationChanged: (page: string) => {
log(`locationChanged: ${page}`);
},
@@ -65,10 +64,11 @@
error: () => {
log('error');
},
- reportExecution: (id: string, details: EventDetails) => {
+ reportExecution: (id: Execution, details?: EventDetails) => {
log(`reportExecution '${id}': ${JSON.stringify(details)}`);
},
- trackApi: (plugin: PluginApi, object: string, method: string) => {
+ trackApi: (pluginApi: PluginApi, object: string, method: string) => {
+ const plugin = pluginApi?.getPluginName() ?? 'unknown';
log(`trackApi '${plugin}', ${object}, ${method}`);
},
reportExtension: () => {},
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.js b/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.js
index 6e56ab1..9b71908 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.js
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_test.js
@@ -322,7 +322,8 @@
test('reportExtension', () => {
service.reportExtension('foo');
assert.isTrue(service.reporter.calledWithExactly(
- 'lifecycle', 'Extension detected', 'foo'
+ 'lifecycle', 'Extension detected', 'Extension detected', undefined,
+ {name: 'foo'}
));
});
@@ -340,6 +341,16 @@
));
});
+ test('trackApi reports same event only once', () => {
+ sinon.spy(service, '_reportEvent');
+ const pluginApi = {getPluginName: () => 'test'};
+ service.trackApi(pluginApi, 'object', 'method');
+ service.trackApi(pluginApi, 'object', 'method');
+ assert.isTrue(service.reporter.calledOnce);
+ service.trackApi(pluginApi, 'object', 'method2');
+ assert.isTrue(service.reporter.calledTwice);
+ });
+
test('report start time', () => {
service.reporter.restore();
sinon.stub(window.performance, 'now').returns(42);
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
index 4742e65..30bf490 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
@@ -24,6 +24,7 @@
AccountInfo,
ActionNameToActionInfoMap,
Base64FileContent,
+ BasePatchSetNum,
BlameInfo,
BranchInfo,
BranchInput,
@@ -422,7 +423,7 @@
): Promise<GetDiffCommentsOutput>;
getDiffComments(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
):
@@ -440,7 +441,7 @@
): Promise<GetDiffRobotCommentsOutput>;
getDiffRobotComments(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
):
@@ -458,7 +459,7 @@
): Promise<GetDiffCommentsOutput>;
getDiffDrafts(
changeNum: NumericChangeId,
- basePatchNum?: PatchSetNum,
+ basePatchNum?: BasePatchSetNum,
patchNum?: PatchSetNum,
path?: string
):
@@ -659,6 +660,7 @@
topic: string,
changeNum: NumericChangeId
): Promise<ChangeInfo[] | undefined>;
+ getChangesWithSimilarTopic(topic: string): Promise<ChangeInfo[] | undefined>;
hasPendingDiffDrafts(): number;
awaitPendingDiffDrafts(): Promise<void>;
diff --git a/polygerrit-ui/app/services/storage/gr-storage.ts b/polygerrit-ui/app/services/storage/gr-storage.ts
new file mode 100644
index 0000000..08a3387
--- /dev/null
+++ b/polygerrit-ui/app/services/storage/gr-storage.ts
@@ -0,0 +1,49 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {CommentRange, PatchSetNum} from '../../types/common';
+
+export interface StorageLocation {
+ changeNum: number;
+ patchNum: PatchSetNum | '@change';
+ path?: string;
+ line?: number;
+ range?: CommentRange;
+}
+
+export interface StorageObject {
+ message?: string;
+ updated: number;
+}
+
+export interface StorageService {
+ getDraftComment(location: StorageLocation): StorageObject | null;
+
+ setDraftComment(location: StorageLocation, message: string): void;
+
+ eraseDraftComment(location: StorageLocation): void;
+
+ getEditableContentItem(key: string): StorageObject | null;
+
+ setEditableContentItem(key: string, message: string): void;
+
+ getRespectfulTipVisibility(): StorageObject | null;
+
+ setRespectfulTipVisibility(delayDays?: number): void;
+
+ eraseEditableContentItem(key: string): void;
+}
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.ts b/polygerrit-ui/app/services/storage/gr-storage_impl.ts
similarity index 72%
rename from polygerrit-ui/app/elements/shared/gr-storage/gr-storage.ts
rename to polygerrit-ui/app/services/storage/gr-storage_impl.ts
index a86d8f2..0c0d151 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.ts
+++ b/polygerrit-ui/app/services/storage/gr-storage_impl.ts
@@ -14,22 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {CommentRange, PatchSetNum} from '../../../types/common';
-export interface StorageLocation {
- changeNum: number;
- patchNum: PatchSetNum | '@change';
- path?: string;
- line?: number;
- range?: CommentRange;
-}
+import {StorageLocation, StorageObject, StorageService} from './gr-storage';
-export interface StorageObject {
- message?: string;
- updated: number;
-}
-
-const DURATION_DAY = 24 * 60 * 60 * 1000;
+export const DURATION_DAY = 24 * 60 * 60 * 1000;
// Clean up old entries no more frequently than one day.
const CLEANUP_THROTTLE_INTERVAL = DURATION_DAY;
@@ -39,7 +27,7 @@
CLEANUP_PREFIXES_MAX_AGE_MAP.set('draft', DURATION_DAY);
CLEANUP_PREFIXES_MAX_AGE_MAP.set('editablecontent', DURATION_DAY);
-export class GrStorage {
+export class GrStorageService implements StorageService {
private lastCleanup = 0;
private readonly storage = window.localStorage;
@@ -47,49 +35,49 @@
private exceededQuota = false;
getDraftComment(location: StorageLocation): StorageObject | null {
- this._cleanupItems();
- return this._getObject(this._getDraftKey(location));
+ this.cleanupItems();
+ return this.getObject(this.getDraftKey(location));
}
setDraftComment(location: StorageLocation, message: string) {
- const key = this._getDraftKey(location);
- this._setObject(key, {message, updated: Date.now()});
+ const key = this.getDraftKey(location);
+ this.setObject(key, {message, updated: Date.now()});
}
eraseDraftComment(location: StorageLocation) {
- const key = this._getDraftKey(location);
+ const key = this.getDraftKey(location);
this.storage.removeItem(key);
}
getEditableContentItem(key: string): StorageObject | null {
- this._cleanupItems();
- return this._getObject(this._getEditableContentKey(key));
+ this.cleanupItems();
+ return this.getObject(this.getEditableContentKey(key));
}
setEditableContentItem(key: string, message: string) {
- this._setObject(this._getEditableContentKey(key), {
+ this.setObject(this.getEditableContentKey(key), {
message,
updated: Date.now(),
});
}
getRespectfulTipVisibility(): StorageObject | null {
- this._cleanupItems();
- return this._getObject('respectfultip:visibility');
+ this.cleanupItems();
+ return this.getObject('respectfultip:visibility');
}
setRespectfulTipVisibility(delayDays = 0) {
- this._cleanupItems();
- this._setObject('respectfultip:visibility', {
+ this.cleanupItems();
+ this.setObject('respectfultip:visibility', {
updated: Date.now() + delayDays * DURATION_DAY,
});
}
eraseEditableContentItem(key: string) {
- this.storage.removeItem(this._getEditableContentKey(key));
+ this.storage.removeItem(this.getEditableContentKey(key));
}
- _getDraftKey(location: StorageLocation): string {
+ private getDraftKey(location: StorageLocation): string {
const range = location.range
? `${location.range.start_line}-${location.range.start_character}` +
`-${location.range.end_character}-${location.range.end_line}`
@@ -107,11 +95,11 @@
return key;
}
- _getEditableContentKey(key: string): string {
+ private getEditableContentKey(key: string): string {
return `editablecontent:${key}`;
}
- _cleanupItems() {
+ private cleanupItems() {
// Throttle cleanup to the throttle interval.
if (
this.lastCleanup &&
@@ -125,7 +113,7 @@
const entries = CLEANUP_PREFIXES_MAX_AGE_MAP.entries();
for (const [prefix, expiration] of entries) {
if (key.startsWith(prefix)) {
- const item = this._getObject(key);
+ const item = this.getObject(key);
if (!item || Date.now() - item.updated > expiration) {
this.storage.removeItem(key);
}
@@ -134,7 +122,7 @@
});
}
- _getObject(key: string): StorageObject | null {
+ private getObject(key: string): StorageObject | null {
const serial = this.storage.getItem(key);
if (!serial) {
return null;
@@ -142,7 +130,7 @@
return JSON.parse(serial) as StorageObject;
}
- _setObject(key: string, obj: StorageObject) {
+ private setObject(key: string, obj: StorageObject) {
if (this.exceededQuota) {
return;
}
diff --git a/polygerrit-ui/app/services/storage/gr-storage_mock.ts b/polygerrit-ui/app/services/storage/gr-storage_mock.ts
new file mode 100644
index 0000000..399ffe4
--- /dev/null
+++ b/polygerrit-ui/app/services/storage/gr-storage_mock.ts
@@ -0,0 +1,86 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {StorageLocation, StorageObject, StorageService} from './gr-storage';
+import {DURATION_DAY} from './gr-storage_impl';
+
+const storage = new Map<string, StorageObject>();
+
+const getDraftKey = (location: StorageLocation): string => {
+ const range = location.range
+ ? `${location.range.start_line}-${location.range.start_character}` +
+ `-${location.range.end_character}-${location.range.end_line}`
+ : null;
+ let key = [
+ 'draft',
+ location.changeNum,
+ location.patchNum,
+ location.path,
+ location.line || '',
+ ].join(':');
+ if (range) {
+ key = key + ':' + range;
+ }
+ return key;
+};
+
+const getEditableContentKey = (key: string): string => `editablecontent:${key}`;
+
+export function cleanUpStorage() {
+ storage.clear();
+}
+
+export const grStorageMock: StorageService = {
+ getDraftComment(location: StorageLocation): StorageObject | null {
+ return storage.get(getDraftKey(location)) ?? null;
+ },
+
+ setDraftComment(location: StorageLocation, message: string) {
+ const key = getDraftKey(location);
+ storage.set(key, {message, updated: Date.now()});
+ },
+
+ eraseDraftComment(location: StorageLocation) {
+ const key = getDraftKey(location);
+ storage.delete(key);
+ },
+
+ getEditableContentItem(key: string): StorageObject | null {
+ return storage.get(getEditableContentKey(key)) ?? null;
+ },
+
+ setEditableContentItem(key: string, message: string): void {
+ storage.set(getEditableContentKey(key), {
+ message,
+ updated: Date.now(),
+ });
+ },
+
+ getRespectfulTipVisibility(): StorageObject | null {
+ return storage.get('respectfultip:visibility') ?? null;
+ },
+
+ setRespectfulTipVisibility(delayDays = 0): void {
+ storage.set('respectfultip:visibility', {
+ updated: Date.now() + delayDays * DURATION_DAY,
+ });
+ },
+
+ eraseEditableContentItem(key: string): void {
+ storage.delete(getEditableContentKey(key));
+ },
+};
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.js b/polygerrit-ui/app/services/storage/gr-storage_test.js
similarity index 87%
rename from polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.js
rename to polygerrit-ui/app/services/storage/gr-storage_test.js
index 64d3750..6cbfacf 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.js
+++ b/polygerrit-ui/app/services/storage/gr-storage_test.js
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import {GrStorage} from './gr-storage.js';
+import '../../test/common-test-setup-karma.js';
+import {GrStorageService} from './gr-storage_impl.js';
suite('gr-storage tests', () => {
let grStorage;
@@ -34,7 +34,7 @@
}
setup(() => {
- grStorage = new GrStorage();
+ grStorage = new GrStorageService();
grStorage.storage = mockStorage();
});
@@ -51,7 +51,7 @@
};
// The key is in the expected format.
- const key = grStorage._getDraftKey(location);
+ const key = grStorage.getDraftKey(location);
assert.equal(key, ['draft', changeNum, patchNum, path, line].join(':'));
// There should be no draft initially.
@@ -82,12 +82,12 @@
line,
};
- const key = grStorage._getDraftKey(location);
+ const key = grStorage.getDraftKey(location);
// Make sure that the call to cleanup doesn't get throttled.
grStorage.lastCleanup = 0;
- const cleanupSpy = sinon.spy(grStorage, '_cleanupItems');
+ const cleanupSpy = sinon.spy(grStorage, 'cleanupItems');
// Create a message with a timestamp that is a second behind the max age.
grStorage.storage.setItem(key, JSON.stringify({
@@ -103,7 +103,7 @@
assert.isNotOk(grStorage.storage.getItem(key));
});
- test('_getDraftKey', () => {
+ test('getDraftKey', () => {
const changeNum = 1234;
const patchNum = 5;
const path = 'my_source_file.js';
@@ -115,7 +115,7 @@
line,
};
let expectedResult = 'draft:1234:5:my_source_file.js:123';
- assert.equal(grStorage._getDraftKey(location), expectedResult);
+ assert.equal(grStorage.getDraftKey(location), expectedResult);
location.range = {
start_character: 1,
start_line: 1,
@@ -123,7 +123,7 @@
end_line: 2,
};
expectedResult = 'draft:1234:5:my_source_file.js:123:1-1-1-2';
- assert.equal(grStorage._getDraftKey(location), expectedResult);
+ assert.equal(grStorage.getDraftKey(location), expectedResult);
});
test('exceeded quota disables storage', () => {
@@ -140,16 +140,16 @@
path,
line,
};
- const key = grStorage._getDraftKey(location);
+ const key = grStorage.getDraftKey(location);
grStorage.setDraftComment(location, 'my comment');
assert.isTrue(grStorage.exceededQuota);
assert.isNotOk(grStorage.storage.getItem(key));
});
test('editable content items', () => {
- const cleanupStub = sinon.stub(grStorage, '_cleanupItems');
+ const cleanupStub = sinon.stub(grStorage, 'cleanupItems');
const key = 'testKey';
- const computedKey = grStorage._getEditableContentKey(key);
+ const computedKey = grStorage.getEditableContentKey(key);
// Key correctly computed.
assert.equal(computedKey, 'editablecontent:testKey');
diff --git a/polygerrit-ui/app/styles/gr-voting-styles.ts b/polygerrit-ui/app/styles/gr-voting-styles.ts
index c1989de..b50aee6 100644
--- a/polygerrit-ui/app/styles/gr-voting-styles.ts
+++ b/polygerrit-ui/app/styles/gr-voting-styles.ts
@@ -27,8 +27,16 @@
<style>
:host {
--vote-chip-styles: {
- border: 1px solid var(--border-color);
- border-radius: 1em;
+ border-style: solid;
+ border-color: var(--border-color);
+ border-top-left-radius: 1em;
+ border-top-right-radius: 1em;
+ border-bottom-right-radius: 1em;
+ border-bottom-left-radius: 1em;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
box-shadow: none;
box-sizing: border-box;
min-width: 3em;
diff --git a/polygerrit-ui/app/styles/shared-styles.ts b/polygerrit-ui/app/styles/shared-styles.ts
index 6d128b3..2af1e46 100644
--- a/polygerrit-ui/app/styles/shared-styles.ts
+++ b/polygerrit-ui/app/styles/shared-styles.ts
@@ -239,16 +239,19 @@
font-family: var(--header-font-family);
-webkit-font-smoothing: initial;
}
- --paper-tab-content-focused: {
- /* paper-tabs uses 700 here, which can look awkward */
- font-weight: var(--font-weight-h3);
- }
--paper-tab-content-unselected: {
/* paper-tabs uses 0.8 here, but we want to control the color directly */
opacity: 1;
color: var(--deemphasized-text-color);
}
}
+ paper-tab {
+ --paper-tab-content-focused: {
+ /* paper-tabs uses 700 here, which can look awkward */
+ font-weight: var(--font-weight-h3);
+ outline: auto;
+ }
+ }
iron-autogrow-textarea {
/** This is needed for firefox */
--iron-autogrow-textarea_-_white-space: pre-wrap;
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 18c12b0..a81dcdf 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -40,72 +40,160 @@
*/
/* color palette */
+ --gerrit-blue-light: #1565c0;
+ --gerrit-blue-dark: #90caf9;
--red-900: #a50e0e;
--red-700: #c5221f;
+ --red-700-04: #c5221f0a;
+ --red-700-10: #c5221f1a;
+ --red-700-12: #c5221f1f;
+ --red-600: #d93025;
+ --red-300: #f28b82;
--red-200: #f6aea9;
--red-50: #fce8e6;
+ --red-tonal: #6c322f;
--blue-900: #174ea6;
+ --blue-800: #185abc;
--blue-700: #1967d2;
+ --blue-700-04: #1967d20a;
+ --blue-700-10: #1967d21a;
+ --blue-700-12: #1967d21f;
+ --blue-700-16: #1967d229;
+ --blue-700-24: #1967d23d;
+ --blue-400: #669df6;
--blue-200: #aecbfa;
+ --blue-200-16: #aecbfa29;
+ --blue-200-24: #aecbfa3d;
+ --blue-100: #d2e3fc;
--blue-50: #e8f0fe;
+ --blue-tonal: #314972;
--orange-900: #b06000;
--orange-700: #d56e0c;
+ --orange-700-04: #d56e0c0a;
+ --orange-700-10: #d56e0c1a;
+ --orange-700-12: #d56e0c1f;
--orange-200: #fdc69c;
--orange-50: #feefe3;
+ --orange-tonal: #714625;
--cyan-900: #007b83;
--cyan-700: #129eaf;
+ --cyan-200: #a1e4f2;
--cyan-100: #cbf0f8;
--cyan-50: #e4f7fb;
+ --cyan-tonal: #275e6b;
--green-900: #0d652d;
--green-700: #188038;
+ --green-700-04: #1880380a;
+ --green-700-10: #1880381a;
+ --green-700-12: #1880381f;
+ --green-400: #5bb974;
+ --green-300: #81c995;
--green-200: #a8dab5;
--green-50: #e6f4ea;
+ --green-tonal: #2c553a;
--gray-900: #202124;
+ --gray-800: #3c4043;
+ --gray-800-12: #3c40431f;
+ --gray-800-38: #3c404361;
--gray-700: #5f6368;
+ --gray-700-04: #5f63680a;
+ --gray-700-10: #5f63681a;
+ --gray-700-12: #5f63681f;
+ --gray-500: #9aa0a6;
--gray-300: #dadce0;
+ --gray-200: #e8eaed;
+ --gray-200-12: #e8eaed1f;
+ --gray-200-38: #e8eaed61;
--gray-100: #f1f3f4;
--gray-50: #f8f9fa;
+ --gray-tonal: #505357;
+ --purple-900: #681da8;
+ --purple-700: #8430ce;
+ --purple-500: #a142f4;
+ --purple-400: #af5cf7;
+ --purple-200: #d7aefb;
+ --purple-50: #f3e8fd;
+ --purple-tonal: #523272;
+ --pink-800: #b80672;
+ --pink-500: #f538a0;
+ --pink-50: #fde7f3;
+ --pink-tonal: #702f55;
+ --yellow-50: #fef7e0;
+ --yellow-tonal: #6a5619;
+ --brown-50: #efebe9;
+ --brown-tonal: #6d4c41;
+ --white-04: #ffffff0a;
+ --white-10: #ffffff1a;
+ --white-12: #ffffff1f;
+
+ --error-foreground: var(--red-700);
+ --error-background: var(--red-50);
+ --error-background-hover: linear-gradient(var(--red-700-04), var(--red-700-04)), var(--red-50);
+ --error-background-focus: linear-gradient(var(--red-700-12), var(--red-700-12)), var(--red-50);
+ --error-ripple: var(--red-700-10);
+
+ --warning-foreground: var(--orange-700);
+ --warning-background: var(--orange-50);
+ --warning-background-hover: linear-gradient(var(--orange-700-04), var(--orange-700-04)), var(--orange-50);
+ --warning-background-focus: linear-gradient(var(--orange-700-12), var(--orange-700-12)), var(--orange-50);
+ --warning-ripple: var(--orange-700-10);
+
+ --info-foreground: var(--blue-700);
+ --info-background: var(--blue-50);
+ --info-background-hover: linear-gradient(var(--blue-700-04), var(--blue-700-04)), var(--blue-50);
+ --info-background-focus: linear-gradient(var(--blue-700-12), var(--blue-700-12)), var(--blue-50);
+ --info-ripple: var(--blue-700-10);
+
+ --primary-button-text-color: white;
+ --primary-button-background-color: var(--gerrit-blue-light);
+ --primary-button-background-hover: var(--blue-700-16);
+ --primary-button-background-focus: var(--blue-700-24);
+
+ --selected-foreground: var(--blue-800);
+ --selected-background: var(--blue-50);
+
+ --success-foreground: var(--green-700);
+ --success-background: var(--green-50);
+ --success-background-hover: linear-gradient(var(--green-700-04), var(--green-700-04)), var(--green-50);
+ --success-background-focus: linear-gradient(var(--green-700-12), var(--green-700-12)), var(--green-50);
+ --success-ripple: var(--green-700-10);
+
+ --gray-foreground: var(--gray-700);
+ --gray-background: var(--gray-100);
+ --gray-background-hover: linear-gradient(var(--gray-700-04), var(--gray-700-04)), var(--gray-100);
+ --gray-background-focus: linear-gradient(var(--gray-700-12), var(--gray-700-12)), var(--gray-100);
+ --gray-ripple: var(--gray-700-10);
+
+ --disabled-foreground: var(--gray-800-38);
+ --disabled-background: var(--gray-800-12);
--chip-color: var(--gray-900);
--error-color: var(--red-900);
- --error-foreground: var(--red-700);
- --error-background: var(--red-50);
- --warning-foreground: var(--orange-700);
- --warning-background: var(--orange-50);
- --info-foreground: var(--blue-700);
- --info-background: var(--blue-50);
- --selected-foreground: var(--blue-700);
- --selected-background: var(--blue-50);
- --success-foreground: var(--green-700);
- --success-background: var(--green-50);
- --gray-foreground: var(--gray-700);
- --gray-background: var(--gray-100);
--tag-background: var(--cyan-100);
--label-background: var(--red-50);
/* text colors */
- --primary-text-color: black;
- --link-color: var(--blue-700);
- --comment-text-color: black;
+ --primary-text-color: var(--gray-900);
+ --link-color: var(--gerrit-blue-light);
+ --comment-text-color: var(--gray-900);
--deemphasized-text-color: var(--gray-700);
- --default-button-text-color: var(--blue-700);
- --chip-selected-text-color: var(--default-button-text-color);
- --error-text-color: red;
- --primary-button-text-color: white;
- /* Used on text color for change list that doesn't need user's attention. */
+ --default-button-text-color: var(--gerrit-blue-light);
+ --chip-selected-text-color: var(--selected-foreground);
+ --error-text-color: var(--red-700);
+ /* Used on text color for change list that doesn't need user's attention. */
--reviewed-text-color: black;
--vote-text-color: black;
--status-text-color: white;
--tooltip-text-color: white;
- --negative-red-text-color: #d93025;
- --positive-green-text-color: #188038;
+ --negative-red-text-color: var(--red-600);
+ --positive-green-text-color: var(--green-700);
--indirect-ancestor-text-color: var(--green-700);
/* background colors */
/* primary background colors */
- --background-color-primary: #ffffff;
- --background-color-secondary: #f8f9fa;
- --background-color-tertiary: #f1f3f4;
+ --background-color-primary: white;
+ --background-color-secondary: var(--gray-50);
+ --background-color-tertiary: var(--gray-100);
/* directly derived from primary background colors */
--chip-background-color: var(--background-color-tertiary);
--default-button-background-color: var(--background-color-primary);
@@ -127,34 +215,53 @@
--edit-mode-background-color: #ebf5fb;
--emphasis-color: #fff9c4;
--hover-background-color: rgba(161, 194, 250, 0.2);
- --disabled-button-background-color: #e8eaed;
- --primary-button-background-color: var(--blue-700);
+ --disabled-button-background-color: var(--disabled-background);
--selection-background-color: rgba(161, 194, 250, 0.1);
- --tooltip-background-color: #333;
+ --tooltip-background-color: var(--gray-900);
+
/* comment background colors */
- --comment-background-color: #e8eaed;
+ --comment-background-color: var(--gray-200);
--robot-comment-background-color: var(--blue-50);
--unresolved-comment-background-color: #fef7e0;
+
/* vote background colors */
- --vote-color-approved: #9fcc6b;
- --vote-color-disliked: #f7c4cb;
- --vote-color-neutral: #ebf5fb;
- --vote-color-recommended: #c9dfaf;
- --vote-color-rejected: #f7a1ad;
+ --vote-color-approved: var(--green-300);
+ --vote-color-disliked: var(--red-50);
+ --vote-outline-disliked: var(--red-700);
+ --vote-color-neutral: var(--gray-300);
+ --vote-color-recommended: var(--green-50);
+ --vote-outline-recommended: var(--green-700);
+ --vote-color-rejected: var(--red-300);
+
+ --outline-color-focus: var(--gray-900);
/* misc colors */
--border-color: var(--gray-300);
--comment-separator-color: var(--gray-300);
+ /* checks tag colors */
+ --tag-gray: var(--gray-200);
+ --tag-yellow: var(--yellow-50);
+ --tag-pink: var(--pink-50);
+ --tag-purple: var(--purple-50);
+ --tag-cyan: var(--cyan-50);
+ --tag-brown: var(--brown-50);
+
/* status colors */
- --status-merged: #188038;
+ --status-merged: var(--green-700);
--status-abandoned: var(--gray-700);
--status-wip: #795548;
- --status-private: #a142f4;
- --status-conflict: #d93025;
- --status-active: #1976d2;
- --status-ready: #b80672;
- --status-custom: #681da8;
+ --status-private: var(--purple-500);
+ --status-conflict: var(--red-600);
+ --status-revert-created: #e64a19;
+ --status-active: var(--blue-700);
+ --status-ready: var(--pink-800);
+ --status-custom: var(--purple-900);
+
+ /* file status colors */
+ --file-status-added: var(--green-300);
+ --file-status-changed: var(--red-200);
+ --file-status-unchanged: var(--grey-300);
/* fonts */
--font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
@@ -179,6 +286,8 @@
--font-weight-h2: 400;
--font-weight-h3: 400;
--context-control-button-font: var(--font-weight-normal) var(--font-size-normal) var(--font-family);
+ --code-hint-font-weight: 500;
+ --image-diff-button-font: var(--font-weight-normal) var(--font-size-normal) var(--font-family);
/* spacing */
--spacing-xxs: 1px;
@@ -219,16 +328,15 @@
--diff-trailing-whitespace-indicator: #ff9ad2;
--light-add-highlight-color: #d8fed8;
--light-rebased-add-highlight-color: #eef;
- --diff-moved-in-background: #e4f7fb;
- --diff-moved-out-background: #f3e8fd;
- --diff-moved-in-label-background: #007b83;
- --diff-moved-out-label-background: #681da8;
+ --diff-moved-in-background: var(--cyan-50);
+ --diff-moved-out-background: var(--purple-50);
+ --diff-moved-in-label-color: var(--cyan-900);
+ --diff-moved-out-label-color: var(--purple-900);
--light-remove-add-highlight-color: #fff8dc;
--light-remove-highlight-color: #ffebee;
--coverage-covered: #e0f2f1;
--coverage-not-covered: #ffd1a4;
- --ranged-comment-chip-background: #b06000;
- --ranged-comment-chip-text-color: #feefe3;
+ --ranged-comment-hint-text-color: var(--orange-900);
/* syntax colors */
--syntax-attr-color: #219;
@@ -268,6 +376,8 @@
/* misc */
--border-radius: 4px;
--reply-overlay-z-index: 1000;
+ /* Base 64 encoded 1x1px of #681da8 */
+ --line-length-indicator: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2PIlF2xAgAD+AHXfBDdKAAAAABJRU5ErkJggg==');
/* paper and iron component overrides */
--iron-overlay-backdrop-background-color: black;
@@ -275,6 +385,16 @@
--iron-overlay-backdrop: {
transition: none;
};
+ --paper-tooltip-delay-in: 200ms;
+ --paper-tooltip-delay-out: 0;
+ --paper-tooltip-duration-in: 0;
+ --paper-tooltip-duration-out: 0;
+ --paper-tooltip-background: var(--tooltip-background-color);
+ --paper-tooltip-opacity: 1.0;
+ --paper-tooltip-text-color: var(--tooltip-text-color);
+ --paper-tooltip: {
+ font-size: var(--font-size-small);
+ }
}
@media screen and (max-width: 50em) {
html {
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index 5455a24..1d20c86 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -36,45 +36,74 @@
* you probably want to override all.
*/
- --chip-color: var(--gray-100);
- --error-color: var(--red-200);
--error-foreground: var(--red-200);
- --error-background: var(--red-900);
+ --error-background: var(--red-tonal);
+ --error-background-hover: linear-gradient(var(--white-04), var(--white-04)), var(--red-tonal);
+ --error-background-focus: linear-gradient(var(--white-12), var(--white-12)), var(--red-tonal);
+ --error-ripple: var(--white-10);
+
--warning-foreground: var(--orange-200);
- --warning-background: var(--orange-900);
+ --warning-background: var(--orange-tonal);
+ --warning-background-hover: linear-gradient(var(--white-04), var(--white-04)), var(--orange-tonal);
+ --warning-background-focus: linear-gradient(var(--white-12), var(--white-12)), var(--orange-tonal);
+ --warning-ripple: var(--white-10);
+
--info-foreground: var(--blue-200);
- --info-background: var(--blue-900);
+ --info-background: var(--blue-tonal);
+ --info-background-hover: linear-gradient(var(--white-04), var(--white-04)), var(--blue-tonal);
+ --info-background-focus: linear-gradient(var(--white-12), var(--white-12)), var(--blue-tonal);
+ --info-ripple: var(--white-10);
+
+ --primary-button-text-color: black;
+ --primary-button-background-color: var(--gerrit-blue-dark);
+ --primary-button-background-hover: var(--blue-200-16);
+ --primary-button-background-focus: var(--blue-200-24);
+
--selected-foreground: var(--blue-200);
--selected-background: var(--blue-900);
+
--success-foreground: var(--green-200);
- --success-background: var(--green-900);
- --gray-foreground: var(--gray-100);
- --gray-background: var(--gray-900);
+ --success-background: var(--green-tonal);
+ --success-background-hover: linear-gradient(var(--white-04), var(--white-04)), var(--green-tonal);
+ --success-background-focus: linear-gradient(var(--white-12), var(--white-12)), var(--green-tonal);
+ --success-ripple: var(--white-10);
+
+ --gray-foreground: var(--gray-300);
+ --gray-background: var(--gray-tonal);
+ --gray-background-hover: linear-gradient(var(--white-04), var(--white-04)), var(--gray-tonal);
+ --gray-background-focus: linear-gradient(var(--white-12), var(--white-12)), var(--gray-tonal);
+ --gray-ripple: var(--white-10);
+
+ --disabled-foreground: var(--gray-200-38);
+ --disabled-background: var(--gray-200-12);
+
+ --chip-color: var(--gray-100);
+ --error-color: var(--red-200);
--tag-background: var(--cyan-900);
--label-background: var(--red-900);
/* text colors */
- --primary-text-color: #e8eaed;
- --link-color: #8ab4f8;
+ --primary-text-color: var(--gray-200);
+ --link-color: var(--gerrit-blue-dark);
--comment-text-color: var(--primary-text-color);
- --deemphasized-text-color: #9aa0a6;
- --default-button-text-color: #8ab4f8;
- --chip-selected-text-color: #d2e3fc;
- --error-text-color: red;
- --primary-button-text-color: black;
- /* Used on text color for change list doesn't need user's attention. */
- --reviewed-text-color: #dadce0;
+ --deemphasized-text-color: var(--gray-500);
+ --default-button-text-color: var(--gerrit-blue-dark);
+ --chip-selected-text-color: var(--blue-100);
+ --error-text-color: var(--red-200);
+ /* Used on text color for change list doesn't need user's attention. */
+ --reviewed-text-color: var(--gray-300);
--vote-text-color: black;
--status-text-color: black;
- --tooltip-text-color: white;
- --negative-red-text-color: #f28b82;
- --positive-green-text-color: #81c995;
+ --tooltip-text-color: var(--gray-200);
+ --negative-red-text-color: var(--red-200);
+ --positive-green-text-color: var(--green-200);
+ --indirect-ancestor-text-color: var(--green-200);
/* background colors */
/* primary background colors */
- --background-color-primary: #202124;
+ --background-color-primary: var(--gray-900);
--background-color-secondary: #2f3034;
- --background-color-tertiary: #3b3d3f;
+ --background-color-tertiary: var(--gray-800);
/* directly derived from primary background colors */
/* empty, because inheriting from app-theme is just fine
/* unique background colors */
@@ -85,33 +114,52 @@
--emphasis-color: #383f4a;
--hover-background-color: rgba(161, 194, 250, 0.2);
--disabled-button-background-color: #484a4d;
- --primary-button-background-color: var(--link-color);
--selection-background-color: rgba(161, 194, 250, 0.1);
- --tooltip-background-color: #111;
+ --tooltip-background-color: var(--gray-800);
+
/* comment background colors */
--comment-background-color: #3c3f43;
--robot-comment-background-color: #1e3a5f;
--unresolved-comment-background-color: #614a19;
+
/* vote background colors */
- --vote-color-approved: #7fb66b;
- --vote-color-disliked: #bf6874;
- --vote-color-neutral: #597280;
- --vote-color-recommended: #3f6732;
- --vote-color-rejected: #ac2d3e;
+ --vote-color-approved: var(--green-300);
+ --vote-color-disliked: var(--red-tonal);
+ --vote-outline-disliked: var(--red-200);
+ --vote-color-neutral: var(--gray-700);
+ --vote-color-recommended: var(--green-tonal);
+ --vote-outline-recommended: var(--green-200);
+ --vote-color-rejected: var(--red-200);
+
+ --outline-color-focus: var(--gray-100);
/* misc colors */
--border-color: var(--gray-700);
--comment-separator-color: var(--border-color);
+ /* checks tag colors */
+ --tag-gray: var(--gray-tonal);
+ --tag-yellow: var(--yellow-tonal);
+ --tag-pink: var(--pink-tonal);
+ --tag-purple: var(--purple-tonal);
+ --tag-cyan: var(--cyan-tonal);
+ --tag-brown: var(--brown-tonal);
+
/* status colors */
- --status-merged: #5bb974;
- --status-abandoned: #dadce0;
+ --status-merged: var(--green-400);
+ --status-abandoned: var(--gray-300);
--status-wip: #bcaaa4;
- --status-private: #d7aefb;
- --status-conflict: #f28b82;
- --status-active: #669df6;
- --status-ready: #f439a0;
- --status-custom: #af5cf7;
+ --status-private: var(--purple-200);
+ --status-conflict: var(--red-300);
+ --status-revert-created: #ff8a65;
+ --status-active: var(--blue-400);
+ --status-ready: var(--pink-500);
+ --status-custom: var(--purple-400);
+
+ /* file status colors */
+ --file-status-added: var(--green-tonal);
+ --file-status-changed: var(--red-tonal);
+ --file-status-unchanged: var(--grey-700);
/* fonts */
--font-weight-bold: 700; /* 700 is the same as 'bold' */
@@ -127,7 +175,7 @@
--header-text-color: var(--primary-text-color);
/* diff colors */
- --dark-add-highlight-color: #133820;
+ --dark-add-highlight-color: var(--green-tonal);
--dark-rebased-add-highlight-color: rgba(11, 255, 155, 0.15);
--dark-rebased-remove-highlight-color: rgba(255, 139, 6, 0.15);
--dark-remove-highlight-color: #62110f;
@@ -140,18 +188,17 @@
--diff-selection-background-color: #3a71d8;
--diff-tab-indicator-color: var(--deemphasized-text-color);
--diff-trailing-whitespace-indicator: #ff9ad2;
- --light-add-highlight-color: #0f401f;
+ --light-add-highlight-color: #182b1f;
--light-rebased-add-highlight-color: #487165;
- --diff-moved-in-background: #006066;
- --diff-moved-out-background: #681da8;
- --diff-moved-in-label-background: #cbf0f8;
- --diff-moved-out-label-background: #e9d2fd;
+ --diff-moved-in-background: #1d4042;
+ --diff-moved-out-background: #230e34;
+ --diff-moved-in-label-color: var(--cyan-50);
+ --diff-moved-out-label-color: var(--purple-50);
--light-remove-add-highlight-color: #2f3f2f;
--light-remove-highlight-color: #320404;
--coverage-covered: #112826;
--coverage-not-covered: #6b3600;
- --ranged-comment-chip-background: #e8f0fe;
- --ranged-comment-chip-text-color: #174ea6;
+ --ranged-comment-hint-text-color: var(--blue-50);
/* syntax colors */
--syntax-attr-color: #80cbbf;
@@ -182,6 +229,8 @@
--syntax-variable-color: #f77669;
/* misc */
+ /* Base 64 encoded 1x1px of #d7aefb; */
+ --line-length-indicator: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2O4vu73fwAIYAOAtqAXCQAAAABJRU5ErkJggg==');
/* paper and iron component overrides */
--iron-overlay-backdrop-background-color: white;
diff --git a/polygerrit-ui/app/styles/themes/dark-theme_test.js b/polygerrit-ui/app/styles/themes/dark-theme_test.ts
similarity index 78%
rename from polygerrit-ui/app/styles/themes/dark-theme_test.js
rename to polygerrit-ui/app/styles/themes/dark-theme_test.ts
index 4f6466f..16e609e 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme_test.js
+++ b/polygerrit-ui/app/styles/themes/dark-theme_test.ts
@@ -15,14 +15,14 @@
* limitations under the License.
*/
-import '../../test/common-test-setup-karma.js';
-import {applyTheme, removeTheme} from './dark-theme.js';
+import '../../test/common-test-setup-karma';
+import {applyTheme, removeTheme} from './dark-theme';
-suite('dark-theme_test.js', () => {
+suite('dark-theme test', () => {
test('apply and remove theme', () => {
applyTheme();
assert.equal(document.head.querySelectorAll('#dark-theme').length, 1);
removeTheme();
- assert.equal(document.head.querySelectorAll('#dark-theme').length, 0);
+ assert.isEmpty(document.head.querySelectorAll('#dark-theme'));
});
});
diff --git a/polygerrit-ui/app/test/common-test-setup.ts b/polygerrit-ui/app/test/common-test-setup.ts
index 4e1662c..641e4b3 100644
--- a/polygerrit-ui/app/test/common-test-setup.ts
+++ b/polygerrit-ui/app/test/common-test-setup.ts
@@ -32,9 +32,8 @@
removeIronOverlayBackdropStyleEl,
TestKeyboardShortcutBinder,
} from './test-utils';
-import {flushDebouncers} from '@polymer/polymer/lib/utils/debounce';
import {_testOnly_getShortcutManagerInstance} from '../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
-import sinon, {SinonSpy} from 'sinon/pkg/sinon-esm';
+import sinon from 'sinon/pkg/sinon-esm';
import {safeTypesBridge} from '../utils/safe-types-util';
import {_testOnly_initGerritPluginApi} from '../elements/shared/gr-js-api-interface/gr-gerrit';
import {initGlobalVariables} from '../elements/gr-app-global-var-init';
@@ -43,6 +42,8 @@
_testOnly_defaultResinReportHandler,
installPolymerResin,
} from '../scripts/polymer-resin-install';
+import {_testOnly_allTasks} from '../utils/async-util';
+import {cleanUpStorage} from '../services/storage/gr-storage_mock';
declare global {
interface Window {
@@ -126,22 +127,18 @@
// For karma always set our implementation
// (karma doesn't provide the stub method)
-function stubImpl<T extends keyof HTMLElementTagNameMap>(
- tagName: T,
- implementation: Partial<HTMLElementTagNameMap[T]>
-) {
+function stubImpl<
+ T extends keyof HTMLElementTagNameMap,
+ K extends keyof HTMLElementTagNameMap[T]
+>(tagName: T, method: K) {
// This method is inspired by web-component-tester method
const proto = document.createElement(tagName).constructor
.prototype as HTMLElementTagNameMap[T];
- const stubs: SinonSpy[] = [];
- for (const [key, value] of Object.entries(implementation)) {
- stubs.push(sinon.stub(proto, key).callsFake(value));
- }
+ const stub = sinon.stub(proto, method);
registerTestCleanup(() => {
- stubs.forEach(stub => {
- stub.restore();
- });
+ stub.restore();
});
+ return stub;
}
window.stub = stubImpl;
@@ -190,19 +187,21 @@
}
}
+function cancelAllTasks() {
+ for (const task of _testOnly_allTasks.values()) {
+ console.warn('ATTENTION! A task was still active at the end of the test!');
+ task.cancel();
+ }
+}
+
teardown(() => {
sinon.restore();
cleanupTestUtils();
TestKeyboardShortcutBinder.pop();
checkGlobalSpace();
removeIronOverlayBackdropStyleEl();
- // Clean Polymer debouncer queue, so next tests will not be affected.
- // WARNING! This will most likely not do what you expect. `flushDebouncers()`
- // will only flush debouncers that were added using `enqueueDebouncer()`. So
- // this will not affect "normal" debouncers that were added using
- // `this.debounce()`. For those please be careful and cancel them using
- // `this.cancelDebouncer()` in the `detached()` lifecycle hook.
- flushDebouncers();
+ cancelAllTasks();
+ cleanUpStorage();
const testTeardownTimestampMs = new Date().getTime();
const elapsedMs = testTeardownTimestampMs - testSetupTimestampMs;
if (elapsedMs > 1000) {
diff --git a/polygerrit-ui/app/test/mocks/comment-api.js b/polygerrit-ui/app/test/mocks/comment-api.js
index f2ca48c..526aabe 100644
--- a/polygerrit-ui/app/test/mocks/comment-api.js
+++ b/polygerrit-ui/app/test/mocks/comment-api.js
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
@@ -23,9 +22,7 @@
* This is an "abstract" class for tests. The descendant must define a template
* for this element and a tagName - see createCommentApiMockWithTemplateElement below
*/
-class CommentApiMock extends GestureEventListeners(
- LegacyElementMixin(
- PolymerElement)) {
+class CommentApiMock extends LegacyElementMixin(PolymerElement) {
static get properties() {
return {
_changeComments: Object,
diff --git a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
index 5efc562..395c9f67 100644
--- a/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
+++ b/polygerrit-ui/app/test/mocks/gr-rest-api_mock.ts
@@ -78,6 +78,7 @@
createConfig,
createPreferences,
createServerInfo,
+ createSubmittedTogetherInfo,
} from '../test-data-generators';
import {
createDefaultDiffPrefs,
@@ -253,11 +254,14 @@
return Promise.resolve([]);
},
getChangesSubmittedTogether(): Promise<SubmittedTogetherInfo | undefined> {
- throw new Error('getChangesSubmittedTogether() not implemented by mock.');
+ return Promise.resolve(createSubmittedTogetherInfo());
},
getChangesWithSameTopic(): Promise<ChangeInfo[] | undefined> {
return Promise.resolve([]);
},
+ getChangesWithSimilarTopic(): Promise<ChangeInfo[] | undefined> {
+ return Promise.resolve([]);
+ },
getConfig(): Promise<ServerInfo | undefined> {
return Promise.resolve(createServerInfo());
},
diff --git a/polygerrit-ui/app/test/test-app-context-init.ts b/polygerrit-ui/app/test/test-app-context-init.ts
index 57afd8a..d74a9c1 100644
--- a/polygerrit-ui/app/test/test-app-context-init.ts
+++ b/polygerrit-ui/app/test/test-app-context-init.ts
@@ -20,6 +20,7 @@
import {grReportingMock} from '../services/gr-reporting/gr-reporting_mock';
import {AppContext, appContext} from '../services/app-context';
import {grRestApiMock} from './mocks/gr-rest-api_mock';
+import {grStorageMock} from '../services/storage/gr-storage_mock';
export function _testOnlyInitAppContext() {
initAppContext();
@@ -36,4 +37,5 @@
}
setMock('reportingService', grReportingMock);
setMock('restApiService', grRestApiMock);
+ setMock('storageService', grStorageMock);
}
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index d2c1cd2..778e58d 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -61,6 +61,12 @@
Requirement,
RequirementType,
UrlEncodedCommentId,
+ BasePatchSetNum,
+ RelatedChangeAndCommitInfo,
+ SubmittedTogetherInfo,
+ RelatedChangesInfo,
+ FixSuggestionInfo,
+ FixId,
} from '../types/common';
import {
AccountsVisibility,
@@ -89,6 +95,7 @@
import {GerritView} from '../services/router/router-model';
import {ChangeComments} from '../elements/diff/gr-comment-api/gr-comment-api';
import {EditRevisionInfo, ParsedChangeInfo} from '../types/types';
+import {ChangeMessage} from '../elements/change/gr-message/gr-message';
export function dateToTimestamp(date: Date): Timestamp {
const nanosecondSuffix = '.000000000';
@@ -200,10 +207,12 @@
};
}
-export function createCommitInfoWithRequiredCommit(): CommitInfoWithRequiredCommit {
+export function createCommitInfoWithRequiredCommit(
+ commit = 'commit'
+): CommitInfoWithRequiredCommit {
return {
...createCommit(),
- commit: 'commit' as CommitId,
+ commit: commit as CommitId,
};
}
@@ -221,12 +230,12 @@
export function createEditRevision(): EditRevisionInfo {
return {
_number: EditPatchSetNum,
- basePatchNum: 1 as PatchSetNum,
+ basePatchNum: 1 as BasePatchSetNum,
commit: createCommit(),
};
}
-export function createChangeMessage(id = 'cm_id_1'): ChangeMessageInfo {
+export function createChangeMessageInfo(id = 'cm_id_1'): ChangeMessageInfo {
return {
id: id as ChangeMessageId,
date: dateToTimestamp(TEST_CHANGE_CREATED),
@@ -234,6 +243,15 @@
};
}
+export function createChangeMessage(id = 'cm_id_1'): ChangeMessage {
+ return {
+ ...createChangeMessageInfo(id),
+ type: '',
+ expanded: false,
+ commentThreads: [],
+ };
+}
+
export function createRevisions(
count: number
): {[revisionId: string]: RevisionInfo} {
@@ -265,7 +283,7 @@
const messageDate = TEST_CHANGE_CREATED;
for (let i = 0; i < count; i++) {
messages.push({
- ...createChangeMessage((i + messageIdStart).toString(16)),
+ ...createChangeMessageInfo((i + messageIdStart).toString(16)),
date: dateToTimestamp(messageDate),
});
messageDate.setDate(messageDate.getDate() + 1);
@@ -358,7 +376,6 @@
return {
has_avatars: false,
js_resource_paths: [],
- html_resource_paths: [],
};
}
@@ -453,6 +470,7 @@
message: 'hello world',
updated: '2018-02-13 22:48:48.018000000' as Timestamp,
unresolved: false,
+ path: 'abc.txt',
};
}
@@ -569,9 +587,40 @@
}
export function createCommentThread(comments: UIComment[]) {
+ if (!comments.length) {
+ throw new Error('comment is required to create a thread');
+ }
comments = comments.map(comment => {
return {...createComment(), ...comment};
});
const threads = createCommentThreads(comments);
- return threads.length > 0 ? threads[0] : {};
+ return threads[0];
+}
+
+export function createRelatedChangeAndCommitInfo(): RelatedChangeAndCommitInfo {
+ return {
+ project: TEST_PROJECT_NAME,
+ commit: createCommitInfoWithRequiredCommit(),
+ };
+}
+
+export function createRelatedChangesInfo(): RelatedChangesInfo {
+ return {
+ changes: [],
+ };
+}
+
+export function createSubmittedTogetherInfo(): SubmittedTogetherInfo {
+ return {
+ changes: [],
+ non_visible_changes: 0,
+ };
+}
+
+export function createFixSuggestionInfo(fixId = 'fix_1'): FixSuggestionInfo {
+ return {
+ fix_id: fixId as FixId,
+ description: `Fix ${fixId}`,
+ replacements: [],
+ };
}
diff --git a/polygerrit-ui/app/test/test-utils.ts b/polygerrit-ui/app/test/test-utils.ts
index 25366fe..26b99ac 100644
--- a/polygerrit-ui/app/test/test-utils.ts
+++ b/polygerrit-ui/app/test/test-utils.ts
@@ -23,6 +23,8 @@
} from '../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {appContext} from '../services/app-context';
import {RestApiService} from '../services/gr-rest-api/gr-rest-api';
+import {SinonSpy} from 'sinon/pkg/sinon-esm';
+import {StorageService} from '../services/storage/gr-storage';
export interface MockPromise extends Promise<unknown> {
resolve: (value?: unknown) => void;
@@ -42,10 +44,31 @@
return getComputedStyle(el).display === 'none';
}
-export function query(el: Element | undefined, selectors: string) {
- if (!el) return null;
- const root = el.shadowRoot || el;
- return root.querySelector(selectors);
+export function queryAll<E extends Element = Element>(
+ el: Element | undefined,
+ selector: string
+): NodeListOf<E> {
+ if (!el) assert.fail('element not defined');
+ const root = el.shadowRoot ?? el;
+ return root.querySelectorAll<E>(selector);
+}
+
+export function query<E extends Element = Element>(
+ el: Element | undefined,
+ selector: string
+): E | undefined {
+ if (!el) return undefined;
+ const root = el.shadowRoot ?? el;
+ return root.querySelector<E>(selector) ?? undefined;
+}
+
+export function queryAndAssert<E extends Element = Element>(
+ el: Element | undefined,
+ selector: string
+): E {
+ const found = query<E>(el, selector);
+ if (!found) assert.fail(`selector '${selector}' did not match anything'`);
+ return found;
}
// Some tests/elements can define its own binding. We want to restore bindings
@@ -143,6 +166,15 @@
return sinon.spy(appContext.restApiService, method);
}
+export function stubStorage<K extends keyof StorageService>(method: K) {
+ return sinon.stub(appContext.storageService, method);
+}
+
+export type SinonSpyMember<F extends (...args: any) => any> = SinonSpy<
+ Parameters<F>,
+ ReturnType<F>
+>;
+
/**
* Forcing an opacity of 0 onto the ironOverlayBackdrop is required, because
* otherwise the backdrop stays around in the DOM for too long waiting for
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index 1bfabf8..9e30484 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -76,12 +76,14 @@
export type ParsedJSON = BrandType<unknown, '_parsedJSON'>;
export type PatchSetNum = BrandType<'PARENT' | 'edit' | number, '_patchSet'>;
+export type BasePatchSetNum = BrandType<'PARENT' | number, '_patchSet'>;
+export type RevisionPatchSetNum = BrandType<'edit' | number, '_patchSet'>;
export type PatchSetNumber = BrandType<number, '_patchSet'>;
-export const EditPatchSetNum = 'edit' as PatchSetNum;
+export const EditPatchSetNum = 'edit' as RevisionPatchSetNum;
// TODO(TS): This is not correct, it is better to have a separate ApiPatchSetNum
// without 'parent'.
-export const ParentPatchSetNum = 'PARENT' as PatchSetNum;
+export const ParentPatchSetNum = 'PARENT' as BasePatchSetNum;
export type ChangeId = BrandType<string, '_changeId'>;
export type ChangeMessageId = BrandType<string, '_changeMessageId'>;
@@ -551,7 +553,7 @@
commit_with_footers?: boolean;
push_certificate?: PushCertificateInfo;
description?: string;
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
}
/**
@@ -747,7 +749,7 @@
export interface AuthInfo {
auth_type: AuthType; // docs incorrectly names it 'type'
use_contributor_agreements?: boolean;
- contributor_agreements?: ContributorAgreementInfo;
+ contributor_agreements?: ContributorAgreementInfo[];
editable_account_fields: EditableAccountField[];
login_url?: string;
login_text?: string;
@@ -1022,9 +1024,8 @@
*/
export interface PluginConfigInfo {
has_avatars: boolean;
- // The following 2 properties exists in Java class, but don't mention in docs
+ // Exists in Java class, but not mentioned in docs.
js_resource_paths: string[];
- html_resource_paths: string[];
}
/**
@@ -1175,6 +1176,7 @@
change_message_id?: string;
commit_id?: string;
context_lines?: ContextLine[];
+ source_content_type?: string;
}
export type PathToCommentsInfoMap = {[path: string]: CommentInfo[]};
@@ -1619,8 +1621,8 @@
* doesn't exist in Rest API
*/
export interface PatchRange {
- patchNum: PatchSetNum;
- basePatchNum: PatchSetNum;
+ patchNum: RevisionPatchSetNum;
+ basePatchNum: BasePatchSetNum;
}
/**
@@ -1764,6 +1766,7 @@
email_strategy: EmailStrategy;
default_base_for_merges: DefaultBase;
publish_comments_on_push?: boolean;
+ disable_keyboard_shortcuts?: boolean;
work_in_progress_by_default?: boolean;
// The email_format doesn't mentioned in doc, but exists in Java class GeneralPreferencesInfo
email_format?: EmailFormat;
@@ -1937,7 +1940,7 @@
*/
export interface EditInfo {
commit: CommitInfo;
- base_patch_set_number: PatchSetNum;
+ base_patch_set_number: BasePatchSetNum;
base_revision: string;
ref: GitRef;
fetch?: ProtocolToFetchInfoMap;
diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts
index 5965453..ff08c57 100644
--- a/polygerrit-ui/app/types/events.ts
+++ b/polygerrit-ui/app/types/events.ts
@@ -20,68 +20,84 @@
import {FetchRequest} from './types';
import {MovedLinkClickedEventDetail} from '../api/diff';
import {Category, RunStatus} from '../api/checks';
+import {ChangeMessage} from '../elements/change/gr-message/gr-message';
-export interface TitleChangeEventDetail {
- title: string;
+export enum EventType {
+ CHANGE_MESSAGE_DELETED = 'change-message-deleted',
+ DIALOG_CHANGE = 'dialog-change',
+ EDITABLE_CONTENT_SAVE = 'editable-content-save',
+ GR_RPC_LOG = 'gr-rpc-log',
+ LOCATION_CHANGE = 'location-change',
+ IRON_ANNOUNCE = 'iron-announce',
+ MOVED_LINK_CLICKED = 'moved-link-clicked',
+ NETWORK_ERROR = 'network-error',
+ OPEN_FIX_PREVIEW = 'open-fix-preview',
+ CLOSE_FIX_PREVIEW = 'close-fix-preview',
+ PAGE_ERROR = 'page-error',
+ RELOAD = 'reload',
+ REPLY = 'reply',
+ SERVER_ERROR = 'server-error',
+ SHORTCUT_TRIGGERERD = 'shortcut-triggered',
+ SHOW_ALERT = 'show-alert',
+ SHOW_ERROR = 'show-error',
+ SHOW_PRIMARY_TAB = 'show-primary-tab',
+ SHOW_SECONDARY_TAB = 'show-secondary-tab',
+ THREAD_LIST_MODIFIED = 'thread-list-modified',
+ TITLE_CHANGE = 'title-change',
}
-export type TitleChangeEvent = CustomEvent<TitleChangeEventDetail>;
-
declare global {
interface HTMLElementEventMap {
+ 'change-message-deleted': ChangeMessageDeletedEvent;
+ 'dialog-change': DialogChangeEvent;
+ 'editable-content-save': EditableContentSaveEvent;
+ 'location-change': LocationChangeEvent;
+ 'iron-announce': IronAnnounceEvent;
+ 'moved-link-clicked': MovedLinkClickedEvent;
+ 'open-fix-preview': OpenFixPreviewEvent;
+ 'close-fix-preview': CloseFixPreviewEvent;
+ /* prettier-ignore */
+ 'reload': ReloadEvent;
+ /* prettier-ignore */
+ 'reply': ReplyEvent;
+ 'shortcut-triggered': ShortcutTriggeredEvent;
+ 'show-alert': ShowAlertEvent;
+ 'show-error': ShowErrorEvent;
+ 'show-primary-tab': SwitchTabEvent;
+ 'show-secondary-tab': SwitchTabEvent;
+ 'thread-list-modified': ThreadListModifiedEvent;
'title-change': TitleChangeEvent;
}
}
-export interface PageErrorEventDetail {
- response: Response;
-}
-
-export type PageErrorEvent = CustomEvent<PageErrorEventDetail>;
-
declare global {
interface DocumentEventMap {
- 'page-error': PageErrorEvent;
- }
-}
-
-export interface ServerErrorEventDetail {
- request?: FetchRequest;
- response: Response;
-}
-
-export type ServerErrorEvent = CustomEvent<ServerErrorEventDetail>;
-
-declare global {
- interface DocumentEventMap {
- 'server-error': ServerErrorEvent;
- }
-}
-
-export interface NetworkErrorEventDetail {
- error: Error;
-}
-
-export type NetworkErrorEvent = CustomEvent<NetworkErrorEventDetail>;
-
-declare global {
- interface DocumentEventMap {
+ 'gr-rpc-log': RpcLogEvent;
'network-error': NetworkErrorEvent;
+ 'page-error': PageErrorEvent;
+ 'server-error': ServerErrorEvent;
+ 'show-alert': ShowAlertEvent;
+ 'show-error': ShowErrorEvent;
}
}
-export interface LocationChangeEventDetail {
- hash: string;
- pathname: string;
+export interface ChangeMessageDeletedEventDetail {
+ message: ChangeMessage;
}
+export type ChangeMessageDeletedEvent = CustomEvent<ChangeMessageDeletedEventDetail>;
-export type LocationChangeEvent = CustomEvent<LocationChangeEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'location-change': LocationChangeEvent;
- }
+// TODO(milutin) - remove once new gr-dialog will do it out of the box
+// This informs gr-app-element to remove footer, header from a11y tree
+export interface DialogChangeEventDetail {
+ canceled?: boolean;
+ opened?: boolean;
}
+export type DialogChangeEvent = CustomEvent<DialogChangeEventDetail>;
+
+export interface EditableContentSaveEventDetail {
+ content: string;
+}
+export type EditableContentSaveEvent = CustomEvent<EditableContentSaveEventDetail>;
export interface RpcLogEventDetail {
status: number | null;
@@ -89,58 +105,81 @@
elapsed: number;
anonymizedUrl: string;
}
-
export type RpcLogEvent = CustomEvent<RpcLogEventDetail>;
-declare global {
- interface DocumentEventMap {
- 'gr-rpc-log': RpcLogEvent;
- }
+export interface IronAnnounceEventDetail {
+ text: string;
}
+export type IronAnnounceEvent = CustomEvent<IronAnnounceEventDetail>;
+
+export interface LocationChangeEventDetail {
+ hash: string;
+ pathname: string;
+}
+export type LocationChangeEvent = CustomEvent<LocationChangeEventDetail>;
+
+export type MovedLinkClickedEvent = CustomEvent<MovedLinkClickedEventDetail>;
+
+export interface NetworkErrorEventDetail {
+ error: Error;
+}
+export type NetworkErrorEvent = CustomEvent<NetworkErrorEventDetail>;
+
+export interface OpenFixPreviewEventDetail {
+ patchNum?: PatchSetNum;
+ comment?: UIComment;
+}
+export type OpenFixPreviewEvent = CustomEvent<OpenFixPreviewEventDetail>;
+
+export interface CloseFixPreviewEventDetail {
+ fixApplied: boolean;
+}
+export type CloseFixPreviewEvent = CustomEvent<CloseFixPreviewEventDetail>;
+
+export interface PageErrorEventDetail {
+ response?: Response;
+}
+export type PageErrorEvent = CustomEvent<PageErrorEventDetail>;
+
+export interface ReloadEventDetail {
+ clearPatchset: boolean;
+}
+export type ReloadEvent = CustomEvent<ReloadEventDetail>;
+
+export interface ReplyEventDetail {
+ message: ChangeMessage;
+}
+export type ReplyEvent = CustomEvent<ReplyEventDetail>;
+
+export interface ServerErrorEventDetail {
+ request?: FetchRequest;
+ response: Response;
+}
+export type ServerErrorEvent = CustomEvent<ServerErrorEventDetail>;
export interface ShortcutTriggeredEventDetail {
event: CustomKeyboardEvent;
goKey: boolean;
vKey: boolean;
}
-
export type ShortcutTriggeredEvent = CustomEvent<ShortcutTriggeredEventDetail>;
-declare global {
- interface HTMLElementEventMap {
- 'shortcut-triggered': ShortcutTriggeredEvent;
- }
+export interface ShowAlertEventDetail {
+ message: string;
+ dismissOnNavigation?: boolean;
+ showDismiss?: boolean;
+ action?: string;
+ callback?: () => void;
}
+export type ShowAlertEvent = CustomEvent<ShowAlertEventDetail>;
-export interface EditableContentSaveEventDetail {
- content: string;
+export interface ShowErrorEventDetail {
+ message: string;
}
-
-export type EditableContentSaveEvent = CustomEvent<
- EditableContentSaveEventDetail
->;
-
-declare global {
- interface HTMLElementEventMap {
- 'editable-content-save': EditableContentSaveEvent;
- }
-}
-
-export interface OpenFixPreviewEventDetail {
- patchNum?: PatchSetNum;
- comment?: UIComment;
-}
-
-export type OpenFixPreviewEvent = CustomEvent<OpenFixPreviewEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'open-fix-preview': OpenFixPreviewEvent;
- }
-}
+export type ShowErrorEvent = CustomEvent<ShowErrorEventDetail>;
// Type for the custom event to switch tab.
-interface SwitchTabEventDetail {
+export interface SwitchTabEventDetail {
// name of the tab to set as active, from custom event
tab?: string;
// index of tab to set as active, from paper-tabs event
@@ -150,68 +189,31 @@
// define state of tab after opening
tabState?: TabState;
}
-
export interface TabState {
commentTab?: CommentTabState;
checksTab?: ChecksTabState;
}
-
export enum CommentTabState {
UNRESOLVED = 'unresolved',
DRAFTS = 'drafts',
SHOW_ALL = 'show all',
}
-
export interface ChecksTabState {
statusOrCategory?: RunStatus | Category;
checkName?: string;
}
-
export type SwitchTabEvent = CustomEvent<SwitchTabEventDetail>;
-declare global {
- interface HTMLElementEventMap {
- 'show-primary-tab': SwitchTabEvent;
- 'show-secondary-tab': SwitchTabEvent;
- }
+export interface ThreadListModifiedDetail {
+ rootId: UrlEncodedCommentId;
+ path: string;
}
+export type ThreadListModifiedEvent = CustomEvent<ThreadListModifiedDetail>;
-export interface ReloadEventDetail {
- clearPatchset: boolean;
+export interface TitleChangeEventDetail {
+ title: string;
}
-
-export type ReloadEvent = CustomEvent<ReloadEventDetail>;
-
-export type MovedLinkClickedEvent = CustomEvent<MovedLinkClickedEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'moved-link-clicked': MovedLinkClickedEvent;
- }
-}
-
-declare global {
- interface HTMLElementEventMap {
- /* prettier-ignore */
- 'reload': ReloadEvent;
- }
-}
-
-export interface ShowAlertEventDetail {
- message: string;
- dismissOnNavigation?: boolean;
- showDismiss?: boolean;
- action?: string;
- callback?: () => void;
-}
-
-export type ShowAlertEvent = CustomEvent<ShowAlertEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'show-alert': ShowAlertEvent;
- }
-}
+export type TitleChangeEvent = CustomEvent<TitleChangeEventDetail>;
/**
* Keyboard events emitted from polymer elements.
@@ -231,25 +233,3 @@
readonly keyCode: number;
readonly repeat: boolean;
}
-
-export interface ThreadListModifiedDetail {
- rootId: UrlEncodedCommentId;
- path: string;
-}
-
-export type ThreadListModifiedEvent = CustomEvent<ThreadListModifiedDetail>;
-
-// TODO(milutin) - remove once new gr-dialog will do it out of the box
-// This informs gr-app-element to remove footer, header from a11y tree
-export interface DialogChangeEventDetail {
- canceled?: boolean;
- opened?: boolean;
-}
-
-export type DialogChangeEvent = CustomEvent<DialogChangeEventDetail>;
-
-declare global {
- interface HTMLElementEventMap {
- 'thread-list-modified': ThreadListModifiedEvent;
- }
-}
diff --git a/polygerrit-ui/app/types/globals.ts b/polygerrit-ui/app/types/globals.ts
index 628cee4..267ea12 100644
--- a/polygerrit-ui/app/types/globals.ts
+++ b/polygerrit-ui/app/types/globals.ts
@@ -32,15 +32,14 @@
// TODO(TS): define gerrit type
Gerrit?: {
Nav?: unknown;
- getRootElement?: unknown;
Auth?: unknown;
- _pluginLoader?: unknown;
- _endpoints?: unknown;
- RevisionInfo?: unknown;
- flushPreinstalls?: () => void;
};
// TODO(TS): define polymer type
- Polymer?: {importHref?: unknown};
+ Polymer: {
+ IronFocusablesHelper: {
+ getTabbableNodes: (el: Element) => Node[];
+ };
+ };
// TODO(TS): remove page when better workaround is found
// page shouldn't be exposed in window and it shouldn't be used
// it's defined because of limitations from typescript, which don't import .mjs
@@ -65,17 +64,8 @@
// TODO(TS): as @brohlfs suggested, to avoid importing anything from elements/ to types/
// use any for them for now
GrAnnotation: unknown;
- GrDiffLine: unknown;
- GrDiffLineType: unknown;
- GrDiffGroup: unknown;
- GrDiffGroupType: unknown;
- util: unknown;
- Auth: unknown;
- EventEmitter: unknown;
- PluginLoader: unknown;
// Heads up! There is a known plugin dependency on GrPluginActionContext.
GrPluginActionContext: unknown;
- _apiUtils: {};
}
interface Performance {
diff --git a/polygerrit-ui/app/types/types.ts b/polygerrit-ui/app/types/types.ts
index be80411..e3e1ada 100644
--- a/polygerrit-ui/app/types/types.ts
+++ b/polygerrit-ui/app/types/types.ts
@@ -21,6 +21,7 @@
import {PaperInputElement} from '@polymer/paper-input/paper-input';
import {
AccountInfo,
+ BasePatchSetNum,
ChangeId,
ChangeViewChangeInfo,
CommitId,
@@ -237,7 +238,7 @@
export interface EditRevisionInfo extends Partial<RevisionInfo> {
// EditRevisionInfo has less required properties then RevisionInfo
_number: PatchSetNum;
- basePatchNum: PatchSetNum;
+ basePatchNum: BasePatchSetNum;
commit: CommitInfo;
}
diff --git a/polygerrit-ui/app/utils/access-util.ts b/polygerrit-ui/app/utils/access-util.ts
index 4af5533..44830e2 100644
--- a/polygerrit-ui/app/utils/access-util.ts
+++ b/polygerrit-ui/app/utils/access-util.ts
@@ -32,7 +32,6 @@
FORGE_COMMITTER = 'forgeCommitter',
FORGE_SERVER_AS_COMMITTER = 'forgeServerAsCommitter',
OWNER = 'owner',
- PUBLISH_DRAFTS = 'publishDrafts',
PUSH = 'push',
PUSH_MERGE = 'pushMerge',
READ = 'read',
@@ -108,10 +107,6 @@
id: AccessPermissionId.OWNER,
name: 'Owner',
},
- [AccessPermissionId.PUBLISH_DRAFTS]: {
- id: AccessPermissionId.PUBLISH_DRAFTS,
- name: 'Publish Drafts',
- },
[AccessPermissionId.PUSH]: {
id: AccessPermissionId.PUSH,
name: 'Push',
diff --git a/polygerrit-ui/app/utils/async-util.ts b/polygerrit-ui/app/utils/async-util.ts
index 119b09b..2b36fee 100644
--- a/polygerrit-ui/app/utils/async-util.ts
+++ b/polygerrit-ui/app/utils/async-util.ts
@@ -42,3 +42,71 @@
return asyncForeach(array.slice(1), fn);
});
}
+
+export const _testOnly_allTasks = new Map<number, DelayedTask>();
+
+/**
+ * This is just a very simple and small wrapper around setTimeout(). Instead of
+ * the usual:
+ *
+ * const timer = window.setTimeout(() => {...do stuff...}, 123);
+ * window.clearTimeout(timer);
+ *
+ * With this class you can do:
+ *
+ * const task = new Task(() => {...do stuff...}, 123);
+ * task.cancel();
+ *
+ * It is just nicer to have an object for this instead of a number as a handle.
+ */
+export class DelayedTask {
+ private timer?: number;
+
+ constructor(private callback: () => void, waitMs = 0) {
+ this.timer = window.setTimeout(() => {
+ if (this.timer) _testOnly_allTasks.delete(this.timer);
+ this.timer = undefined;
+ if (this.callback) this.callback();
+ }, waitMs);
+ _testOnly_allTasks.set(this.timer, this);
+ }
+
+ cancel() {
+ if (this.isActive()) {
+ window.clearTimeout(this.timer);
+ if (this.timer) _testOnly_allTasks.delete(this.timer);
+ this.timer = undefined;
+ }
+ }
+
+ flush() {
+ if (this.isActive()) {
+ this.cancel();
+ if (this.callback) this.callback();
+ }
+ }
+
+ isActive() {
+ return this.timer !== undefined;
+ }
+}
+
+/**
+ * The usage pattern is:
+ *
+ * this.myDebouncedTask = debounce(this.myDebouncedTask, () => {...}, 123);
+ *
+ * It is identical to:
+ *
+ * this.myTask = new DelayedTask(() => {...}, 123);
+ *
+ * But it would cancel a potentially scheduled task beforehand.
+ */
+export function debounce(
+ existingTask: DelayedTask | undefined,
+ callback: () => void,
+ waitMs = 0
+) {
+ existingTask?.cancel();
+ return new DelayedTask(callback, waitMs);
+}
diff --git a/polygerrit-ui/app/utils/change-metadata-util.ts b/polygerrit-ui/app/utils/change-metadata-util.ts
index c3eb846..9692ab31 100644
--- a/polygerrit-ui/app/utils/change-metadata-util.ts
+++ b/polygerrit-ui/app/utils/change-metadata-util.ts
@@ -23,6 +23,8 @@
REPO_BRANCH = 'Repo | Branch',
SUBMITTED = 'Submitted',
PARENT = 'Parent',
+ MERGED_AS = 'Merged as',
+ REVERT_CREATED_AS = 'Revert Created as',
STRATEGY = 'Strategy',
UPDATED = 'Updated',
CC = 'CC',
@@ -41,18 +43,24 @@
Metadata.REVIEWERS,
Metadata.REPO_BRANCH,
Metadata.SUBMITTED,
+ Metadata.TOPIC,
],
SHOW_IF_SET: [
Metadata.CC,
Metadata.HASHTAGS,
- Metadata.TOPIC,
Metadata.UPLOADER,
Metadata.AUTHOR,
Metadata.COMMITTER,
Metadata.ASSIGNEE,
Metadata.CHERRY_PICK_OF,
],
- ALWAYS_HIDE: [Metadata.PARENT, Metadata.STRATEGY, Metadata.UPDATED],
+ ALWAYS_HIDE: [
+ Metadata.PARENT,
+ Metadata.MERGED_AS,
+ Metadata.REVERT_CREATED_AS,
+ Metadata.STRATEGY,
+ Metadata.UPDATED,
+ ],
};
export function isSectionSet(section: Metadata, change?: ParsedChangeInfo) {
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index a7f8b49..b2d23a0 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -24,6 +24,7 @@
RelatedChangeAndCommitInfo,
} from '../types/common';
import {ParsedChangeInfo} from '../types/types';
+import {isRevertCreated} from './message-util';
// This can be wrong! See WARNING above
interface ChangeStatusesOptions {
@@ -134,6 +135,7 @@
return change?.status === ChangeStatus.NEW;
}
+// TODO(TS): use enum ChangeStates in gr-change-status
export function changeStatuses(
change: ChangeInfo,
opt_options?: ChangeStatusesOptions
@@ -156,6 +158,9 @@
if (change.is_private) {
states.push('Private');
}
+ if (isRevertCreated(change.messages)) {
+ states.push('Revert Created');
+ }
// If there are any pre-defined statuses, only return those. Otherwise,
// will determine the derived status.
@@ -213,7 +218,7 @@
return owner || uploader || reviewer || cc;
}
-export function getCurrentRevision(change?: ChangeInfo) {
+export function getCurrentRevision(change?: ChangeInfo | ParsedChangeInfo) {
if (!change?.revisions || !change?.current_revision) return undefined;
return change.revisions[change.current_revision];
}
@@ -227,10 +232,6 @@
);
}
-export function changeStatusString(change: ChangeInfo) {
- return changeStatuses(change).join(', ');
-}
-
export function isRemovableReviewer(
change?: ChangeInfo,
reviewer?: AccountInfo
diff --git a/polygerrit-ui/app/utils/change-util_test.js b/polygerrit-ui/app/utils/change-util_test.js
index fd181fe..f348239 100644
--- a/polygerrit-ui/app/utils/change-util_test.js
+++ b/polygerrit-ui/app/utils/change-util_test.js
@@ -20,7 +20,6 @@
changeBaseURL,
changePath,
changeStatuses,
- changeStatusString,
isRemovableReviewer,
} from './change-util.js';
@@ -59,9 +58,7 @@
mergeable: true,
};
let statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, []);
- assert.equal(statusString, '');
change.submittable = false;
statuses = changeStatuses(change,
@@ -109,9 +106,7 @@
mergeable: false,
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, ['Merge Conflict']);
- assert.equal(statusString, 'Merge Conflict');
});
test('mergeable prop undefined', () => {
@@ -125,9 +120,7 @@
labels: {},
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, []);
- assert.equal(statusString, '');
});
test('Merged status', () => {
@@ -141,9 +134,7 @@
labels: {},
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, ['Merged']);
- assert.equal(statusString, 'Merged');
});
test('Abandoned status', () => {
@@ -157,9 +148,7 @@
labels: {},
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, ['Abandoned']);
- assert.equal(statusString, 'Abandoned');
});
test('Open status with private and wip', () => {
@@ -176,9 +165,7 @@
mergeable: true,
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, ['WIP', 'Private']);
- assert.equal(statusString, 'WIP, Private');
});
test('Merge conflict with private and wip', () => {
@@ -195,9 +182,7 @@
mergeable: false,
};
const statuses = changeStatuses(change);
- const statusString = changeStatusString(change);
assert.deepEqual(statuses, ['Merge Conflict', 'WIP', 'Private']);
- assert.equal(statusString, 'Merge Conflict, WIP, Private');
});
test('isRemovableReviewer', () => {
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index de12a2a..048206b 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -25,6 +25,8 @@
PatchRange,
ParentPatchSetNum,
ContextLine,
+ BasePatchSetNum,
+ RevisionPatchSetNum,
} from '../types/common';
import {CommentSide, Side} from '../constants/constants';
import {parseDate} from './date-util';
@@ -265,14 +267,16 @@
export function getPatchRangeForCommentUrl(
comment: UIComment,
- latestPatchNum: PatchSetNum
+ latestPatchNum: RevisionPatchSetNum
) {
if (!comment.patch_set) throw new Error('Missing comment.patch_set');
// TODO(dhruvsri): Add handling for comment left on parents of merge commits
if (comment.side === CommentSide.PARENT) {
+ if (comment.patch_set === ParentPatchSetNum)
+ throw new Error('diffSide cannot be PARENT');
return {
- patchNum: comment.patch_set,
+ patchNum: comment.patch_set as RevisionPatchSetNum,
basePatchNum: ParentPatchSetNum,
};
} else if (latestPatchNum === comment.patch_set) {
@@ -282,13 +286,17 @@
};
} else {
return {
- patchNum: latestPatchNum,
- basePatchNum: comment.patch_set,
+ patchNum: latestPatchNum as RevisionPatchSetNum,
+ basePatchNum: comment.patch_set as BasePatchSetNum,
};
}
}
-export function computeDiffFromContext(context: ContextLine[], path: string) {
+export function computeDiffFromContext(
+ context: ContextLine[],
+ path: string,
+ content_type?: string
+) {
// do not render more than 20 lines of context
context = context.slice(0, 20);
const diff: DiffInfo = {
@@ -300,7 +308,7 @@
},
meta_b: {
name: path,
- content_type: '',
+ content_type: content_type || '',
lines: context.length + context?.[0].line_number,
web_links: [],
},
diff --git a/polygerrit-ui/app/utils/comment-util_test.js b/polygerrit-ui/app/utils/comment-util_test.js
deleted file mode 100644
index 4ce95ef..0000000
--- a/polygerrit-ui/app/utils/comment-util_test.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../test/common-test-setup-karma.js';
-import {
- isUnresolved, getPatchRangeForCommentUrl, createCommentThreads, sortComments,
-} from './comment-util.js';
-import {createComment} from '../test/test-data-generators.js';
-import {CommentSide, Side} from '../constants/constants.js';
-import {ParentPatchSetNum} from '../types/common.js';
-
-suite('comment-util', () => {
- test('isUnresolved', () => {
- assert.isFalse(isUnresolved(undefined));
- assert.isFalse(isUnresolved({comments: []}));
- assert.isTrue(isUnresolved({comments: [{unresolved: true}]}));
- assert.isFalse(isUnresolved({comments: [{unresolved: false}]}));
- assert.isTrue(isUnresolved(
- {comments: [{unresolved: false}, {unresolved: true}]}));
- assert.isFalse(isUnresolved(
- {comments: [{unresolved: true}, {unresolved: false}]}));
- });
-
- test('getPatchRangeForCommentUrl', () => {
- test('comment created with side=PARENT does not navigate to latest ps',
- () => {
- const comment = {
- ...createComment(),
- id: 'c4',
- line: 10,
- patch_set: 4,
- side: CommentSide.PARENT,
- path: '/COMMIT_MSG',
- };
- assert.deepEqual(getPatchRangeForCommentUrl(comment, 11), {
- basePatchNum: ParentPatchSetNum,
- patchNum: 4,
- });
- });
- });
-
- test('comments sorting', () => {
- const comments = [
- {
- id: 'new_draft',
- message: 'i do not like either of you',
- diffSide: Side.LEFT,
- __draft: true,
- updated: '2015-12-20 15:01:20.396000000',
- },
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- line: 1,
- diffSide: Side.LEFT,
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- diffSide: Side.LEFT,
- line: 1,
- in_reply_to: 'sallys_confession',
- },
- ];
- const sortedComments = sortComments(comments);
- assert.equal(sortedComments[0], comments[1]);
- assert.equal(sortedComments[1], comments[2]);
- assert.equal(sortedComments[2], comments[0]);
- });
-
- suite('createCommentThreads', () => {
- test('creates threads from individual comments', () => {
- const comments = [
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- line: 1,
- patch_set: 1,
- path: 'some/path',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- line: 1,
- in_reply_to: 'sallys_confession',
- patch_set: 1,
- path: 'some/path',
- },
- {
- id: 'new_draft',
- message: 'i do not like either of you',
- __draft: true,
- updated: '2015-12-20 15:01:20.396000000',
- patch_set: 1,
- path: 'some/path',
- },
- ];
-
- const actualThreads = createCommentThreads(comments,
- {basePatchNum: 1, patchNum: 4});
-
- assert.equal(actualThreads.length, 2);
-
- assert.equal(actualThreads[0].diffSide, Side.LEFT);
- assert.equal(actualThreads[0].comments.length, 2);
- assert.deepEqual(actualThreads[0].comments[0], comments[0]);
- assert.deepEqual(actualThreads[0].comments[1], comments[1]);
- assert.equal(actualThreads[0].patchNum, 1);
- assert.equal(actualThreads[0].line, 1);
-
- assert.equal(actualThreads[1].diffSide, Side.LEFT);
- assert.equal(actualThreads[1].comments.length, 1);
- assert.deepEqual(actualThreads[1].comments[0], comments[2]);
- assert.equal(actualThreads[1].patchNum, 1);
- assert.equal(actualThreads[1].line, 'FILE');
- });
-
- test('derives patchNum and range', () => {
- const comments = [{
- id: 'betsys_confession',
- message: 'i like you, jack',
- updated: '2015-12-24 15:00:10.396000000',
- range: {
- start_line: 1,
- start_character: 1,
- end_line: 1,
- end_character: 2,
- },
- patch_set: 5,
- path: '/p',
- line: 1,
- }];
-
- const expectedThreads = [
- {
- diffSide: Side.LEFT,
- commentSide: CommentSide.REVISION,
- path: '/p',
- rootId: 'betsys_confession',
- mergeParentNum: undefined,
- comments: [{
- id: 'betsys_confession',
- path: '/p',
- message: 'i like you, jack',
- updated: '2015-12-24 15:00:10.396000000',
- range: {
- start_line: 1,
- start_character: 1,
- end_line: 1,
- end_character: 2,
- },
- patch_set: 5,
- line: 1,
- }],
- patchNum: 5,
- range: {
- start_line: 1,
- start_character: 1,
- end_line: 1,
- end_character: 2,
- },
- line: 1,
- },
- ];
-
- assert.deepEqual(
- createCommentThreads(comments, {basePatchNum: 5, patchNum: 10}),
- expectedThreads);
- });
-
- test('does not thread unrelated comments at same location', () => {
- const comments = [
- {
- id: 'sallys_confession',
- message: 'i like you, jack',
- updated: '2015-12-23 15:00:20.396000000',
- diffSide: Side.LEFT,
- path: '/p',
- }, {
- id: 'jacks_reply',
- message: 'i like you, too',
- updated: '2015-12-24 15:01:20.396000000',
- diffSide: Side.LEFT,
- path: '/p',
- },
- ];
- assert.equal(createCommentThreads(comments).length, 2);
- });
- });
-});
diff --git a/polygerrit-ui/app/utils/comment-util_test.ts b/polygerrit-ui/app/utils/comment-util_test.ts
new file mode 100644
index 0000000..3c8f26d
--- /dev/null
+++ b/polygerrit-ui/app/utils/comment-util_test.ts
@@ -0,0 +1,258 @@
+/**
+ * @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';
+import {
+ isUnresolved,
+ getPatchRangeForCommentUrl,
+ createCommentThreads,
+ sortComments,
+} from './comment-util';
+import {createComment, createCommentThread} from '../test/test-data-generators';
+import {CommentSide, Side} from '../constants/constants';
+import {
+ BasePatchSetNum,
+ ParentPatchSetNum,
+ PatchSetNum,
+ RevisionPatchSetNum,
+ Timestamp,
+ UrlEncodedCommentId,
+} from '../types/common';
+
+suite('comment-util', () => {
+ test('isUnresolved', () => {
+ const thread = createCommentThread([createComment()]);
+
+ assert.isFalse(isUnresolved(undefined));
+ assert.isFalse(isUnresolved(thread));
+
+ assert.isTrue(
+ isUnresolved({
+ ...thread,
+ comments: [{...createComment(), unresolved: true}],
+ })
+ );
+ assert.isFalse(
+ isUnresolved({
+ ...thread,
+ comments: [{...createComment(), unresolved: false}],
+ })
+ );
+ assert.isTrue(
+ isUnresolved({
+ ...thread,
+ comments: [
+ {...createComment(), unresolved: false},
+ {...createComment(), unresolved: true},
+ ],
+ })
+ );
+ assert.isFalse(
+ isUnresolved({
+ ...thread,
+ comments: [
+ {...createComment(), unresolved: true},
+ {...createComment(), unresolved: false},
+ ],
+ })
+ );
+ });
+
+ test('getPatchRangeForCommentUrl', () => {
+ test('comment created with side=PARENT does not navigate to latest ps', () => {
+ const comment = {
+ ...createComment(),
+ id: 'c4' as UrlEncodedCommentId,
+ line: 10,
+ patch_set: 4 as PatchSetNum,
+ side: CommentSide.PARENT,
+ path: '/COMMIT_MSG',
+ };
+ assert.deepEqual(
+ getPatchRangeForCommentUrl(comment, 11 as RevisionPatchSetNum),
+ {
+ basePatchNum: ParentPatchSetNum,
+ patchNum: 4 as PatchSetNum,
+ }
+ );
+ });
+ });
+
+ test('comments sorting', () => {
+ const comments = [
+ {
+ id: 'new_draft' as UrlEncodedCommentId,
+ message: 'i do not like either of you',
+ diffSide: Side.LEFT,
+ __draft: true,
+ updated: '2015-12-20 15:01:20.396000000' as Timestamp,
+ },
+ {
+ id: 'sallys_confession' as UrlEncodedCommentId,
+ message: 'i like you, jack',
+ updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+ line: 1,
+ diffSide: Side.LEFT,
+ },
+ {
+ id: 'jacks_reply' as UrlEncodedCommentId,
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+ diffSide: Side.LEFT,
+ line: 1,
+ in_reply_to: 'sallys_confession',
+ },
+ ];
+ const sortedComments = sortComments(comments);
+ assert.equal(sortedComments[0], comments[1]);
+ assert.equal(sortedComments[1], comments[2]);
+ assert.equal(sortedComments[2], comments[0]);
+ });
+
+ suite('createCommentThreads', () => {
+ test('creates threads from individual comments', () => {
+ const comments = [
+ {
+ id: 'sallys_confession' as UrlEncodedCommentId,
+ message: 'i like you, jack',
+ updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+ line: 1,
+ patch_set: 1 as PatchSetNum,
+ path: 'some/path',
+ },
+ {
+ id: 'jacks_reply' as UrlEncodedCommentId,
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+ line: 1,
+ in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
+ patch_set: 1 as PatchSetNum,
+ path: 'some/path',
+ },
+ {
+ id: 'new_draft' as UrlEncodedCommentId,
+ message: 'i do not like either of you' as UrlEncodedCommentId,
+ __draft: true,
+ updated: '2015-12-20 15:01:20.396000000' as Timestamp,
+ patch_set: 1 as PatchSetNum,
+ path: 'some/path',
+ },
+ ];
+
+ const actualThreads = createCommentThreads(comments, {
+ basePatchNum: 1 as BasePatchSetNum,
+ patchNum: 4 as RevisionPatchSetNum,
+ });
+
+ assert.equal(actualThreads.length, 2);
+
+ assert.equal(actualThreads[0].diffSide, Side.LEFT);
+ assert.equal(actualThreads[0].comments.length, 2);
+ assert.deepEqual(actualThreads[0].comments[0], comments[0]);
+ assert.deepEqual(actualThreads[0].comments[1], comments[1]);
+ assert.equal(actualThreads[0].patchNum, 1 as PatchSetNum);
+ assert.equal(actualThreads[0].line, 1);
+
+ assert.equal(actualThreads[1].diffSide, Side.LEFT);
+ assert.equal(actualThreads[1].comments.length, 1);
+ assert.deepEqual(actualThreads[1].comments[0], comments[2]);
+ assert.equal(actualThreads[1].patchNum, 1 as PatchSetNum);
+ assert.equal(actualThreads[1].line, 'FILE');
+ });
+
+ test('derives patchNum and range', () => {
+ const comments = [
+ {
+ id: 'betsys_confession' as UrlEncodedCommentId,
+ message: 'i like you, jack',
+ updated: '2015-12-24 15:00:10.396000000' as Timestamp,
+ range: {
+ start_line: 1,
+ start_character: 1,
+ end_line: 1,
+ end_character: 2,
+ },
+ patch_set: 5 as PatchSetNum,
+ path: '/p',
+ line: 1,
+ },
+ ];
+
+ const expectedThreads = [
+ {
+ diffSide: Side.LEFT,
+ commentSide: CommentSide.REVISION,
+ path: '/p',
+ rootId: 'betsys_confession' as UrlEncodedCommentId,
+ mergeParentNum: undefined,
+ comments: [
+ {
+ id: 'betsys_confession' as UrlEncodedCommentId,
+ path: '/p',
+ message: 'i like you, jack',
+ updated: '2015-12-24 15:00:10.396000000' as Timestamp,
+ range: {
+ start_line: 1,
+ start_character: 1,
+ end_line: 1,
+ end_character: 2,
+ },
+ patch_set: 5 as PatchSetNum,
+ line: 1,
+ },
+ ],
+ patchNum: 5 as PatchSetNum,
+ range: {
+ start_line: 1,
+ start_character: 1,
+ end_line: 1,
+ end_character: 2,
+ },
+ line: 1,
+ },
+ ];
+
+ assert.deepEqual(
+ createCommentThreads(comments, {
+ basePatchNum: 5 as BasePatchSetNum,
+ patchNum: 10 as RevisionPatchSetNum,
+ }),
+ expectedThreads
+ );
+ });
+
+ test('does not thread unrelated comments at same location', () => {
+ const comments = [
+ {
+ id: 'sallys_confession' as UrlEncodedCommentId,
+ message: 'i like you, jack',
+ updated: '2015-12-23 15:00:20.396000000' as Timestamp,
+ diffSide: Side.LEFT,
+ path: '/p',
+ },
+ {
+ id: 'jacks_reply' as UrlEncodedCommentId,
+ message: 'i like you, too',
+ updated: '2015-12-24 15:01:20.396000000' as Timestamp,
+ diffSide: Side.LEFT,
+ path: '/p',
+ },
+ ];
+ assert.equal(createCommentThreads(comments).length, 2);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/utils/common-util.ts b/polygerrit-ui/app/utils/common-util.ts
index f4d6d51..08b5e49 100644
--- a/polygerrit-ui/app/utils/common-util.ts
+++ b/polygerrit-ui/app/utils/common-util.ts
@@ -122,3 +122,7 @@
set.add(value);
}
}
+
+export function unique<T>(item: T, index: number, array: T[]) {
+ return array.indexOf(item) === index;
+}
diff --git a/polygerrit-ui/app/utils/date-util.ts b/polygerrit-ui/app/utils/date-util.ts
index 3af8c59..a780af5 100644
--- a/polygerrit-ui/app/utils/date-util.ts
+++ b/polygerrit-ui/app/utils/date-util.ts
@@ -90,15 +90,6 @@
const diff = now.valueOf() - date.valueOf();
return diff < 180 * Duration.DAY;
}
-interface Options {
- month?: string;
- year?: string;
- day?: string;
- hour?: string;
- hour12?: boolean;
- minute?: string;
- second?: string;
-}
// TODO(dmfilippov): TS-Fix review this type. All fields here must be optional,
// but this require some changes in the code. During JS->TS migration
@@ -118,7 +109,7 @@
}
export function formatDate(date: Date, format: string) {
- const options: Options = {};
+ const options: Intl.DateTimeFormatOptions = {};
if (format.includes('MM')) {
if (format.includes('MMM')) {
options.month = 'short';
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index 7f9ef72..3affef7 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -278,3 +278,17 @@
);
observer.observe(element);
}
+
+/**
+ * Toggles a CSS class on or off for an element.
+ */
+export function toggleClass(el: Element, className: string, bool?: boolean) {
+ if (bool === undefined) {
+ bool = !el.classList.contains(className);
+ }
+ if (bool) {
+ el.classList.add(className);
+ } else {
+ el.classList.remove(className);
+ }
+}
diff --git a/polygerrit-ui/app/utils/event-util.ts b/polygerrit-ui/app/utils/event-util.ts
index cf590e0..da075f1 100644
--- a/polygerrit-ui/app/utils/event-util.ts
+++ b/polygerrit-ui/app/utils/event-util.ts
@@ -17,18 +17,12 @@
import {UrlEncodedCommentId} from '../types/common';
import {FetchRequest} from '../types/types';
-import {DialogChangeEventDetail, TabState} from '../types/events';
-
-export enum EventType {
- SHOW_ALERT = 'show-alert',
- PAGE_ERROR = 'page-error',
- SERVER_ERROR = 'server-error',
- NETWORK_ERROR = 'network-error',
- TITLE_CHANGE = 'title-change',
- THREAD_LIST_MODIFIED = 'thread-list-modified',
- DIALOG_CHANGE = 'dialog-change',
- SHOW_PRIMARY_TAB = 'show-primary-tab',
-}
+import {
+ DialogChangeEventDetail,
+ EventType,
+ SwitchTabEventDetail,
+ TabState,
+} from '../types/events';
export function fireEvent(target: EventTarget, type: string) {
target.dispatchEvent(
@@ -39,54 +33,66 @@
);
}
-export function fireAlert(target: EventTarget, message: string) {
+type HTMLElementEventDetailType<
+ K extends keyof HTMLElementEventMap
+> = HTMLElementEventMap[K] extends CustomEvent<infer DT>
+ ? unknown extends DT
+ ? never
+ : DT
+ : never;
+
+type DocumentEventDetailType<
+ K extends keyof DocumentEventMap
+> = DocumentEventMap[K] extends CustomEvent<infer DT>
+ ? unknown extends DT
+ ? never
+ : DT
+ : never;
+
+export function fire<K extends keyof DocumentEventMap>(
+ target: Document,
+ type: K,
+ detail: DocumentEventDetailType<K>
+): void;
+
+export function fire<K extends keyof HTMLElementEventMap>(
+ target: EventTarget,
+ type: K,
+ detail: HTMLElementEventDetailType<K>
+): void;
+
+export function fire<T>(target: EventTarget, type: string, detail: T) {
target.dispatchEvent(
- new CustomEvent(EventType.SHOW_ALERT, {
- detail: {message},
+ new CustomEvent<T>(type, {
+ detail,
composed: true,
bubbles: true,
})
);
}
+export function fireAlert(target: EventTarget, message: string) {
+ fire(target, EventType.SHOW_ALERT, {message});
+}
+
export function firePageError(response?: Response | null) {
- document.dispatchEvent(
- new CustomEvent(EventType.PAGE_ERROR, {
- detail: {response},
- composed: true,
- bubbles: true,
- })
- );
+ if (response === null) response = undefined;
+ fire(document, EventType.PAGE_ERROR, {response});
}
export function fireServerError(response: Response, request?: FetchRequest) {
- document.dispatchEvent(
- new CustomEvent(EventType.SERVER_ERROR, {
- detail: {response, request},
- composed: true,
- bubbles: true,
- })
- );
+ fire(document, EventType.SERVER_ERROR, {
+ response,
+ request,
+ });
}
export function fireNetworkError(error: Error) {
- document.dispatchEvent(
- new CustomEvent(EventType.NETWORK_ERROR, {
- detail: {error},
- composed: true,
- bubbles: true,
- })
- );
+ fire(document, EventType.NETWORK_ERROR, {error});
}
export function fireTitleChange(target: EventTarget, title: string) {
- target.dispatchEvent(
- new CustomEvent(EventType.TITLE_CHANGE, {
- detail: {title},
- composed: true,
- bubbles: true,
- })
- );
+ fire(target, EventType.TITLE_CHANGE, {title});
}
// TODO(milutin) - remove once new gr-dialog will do it out of the box
@@ -95,13 +101,11 @@
target: EventTarget,
detail: DialogChangeEventDetail
) {
- target.dispatchEvent(
- new CustomEvent(EventType.DIALOG_CHANGE, {
- detail,
- composed: true,
- bubbles: true,
- })
- );
+ fire(target, EventType.DIALOG_CHANGE, detail);
+}
+
+export function fireIronAnnounce(target: EventTarget, text: string) {
+ fire(target, EventType.IRON_ANNOUNCE, {text});
}
export function fireThreadListModifiedEvent(
@@ -109,13 +113,10 @@
rootId: UrlEncodedCommentId,
path: string
) {
- target.dispatchEvent(
- new CustomEvent(EventType.THREAD_LIST_MODIFIED, {
- detail: {rootId, path},
- composed: true,
- bubbles: true,
- })
- );
+ fire(target, EventType.THREAD_LIST_MODIFIED, {
+ rootId,
+ path,
+ });
}
export function fireShowPrimaryTab(
@@ -124,11 +125,22 @@
scrollIntoView?: boolean,
tabState?: TabState
) {
- target.dispatchEvent(
- new CustomEvent(EventType.SHOW_PRIMARY_TAB, {
- detail: {tab, scrollIntoView, tabState},
- composed: true,
- bubbles: true,
- })
- );
+ const detail: SwitchTabEventDetail = {tab, scrollIntoView, tabState};
+ fire(target, EventType.SHOW_PRIMARY_TAB, detail);
+}
+
+export function fireCloseFixPreview(target: EventTarget, fixApplied: boolean) {
+ fire(target, EventType.CLOSE_FIX_PREVIEW, {fixApplied});
+}
+
+export function waitForEventOnce<K extends keyof HTMLElementEventMap>(
+ el: EventTarget,
+ eventName: K
+): Promise<HTMLElementEventMap[K]> {
+ return new Promise<HTMLElementEventMap[K]>(resolve => {
+ const callback = (event: HTMLElementEventMap[K]) => {
+ resolve(event);
+ };
+ el.addEventListener(eventName, callback as EventListener, {once: true});
+ });
}
diff --git a/polygerrit-ui/app/utils/message-util.ts b/polygerrit-ui/app/utils/message-util.ts
new file mode 100644
index 0000000..f2d7e6b
--- /dev/null
+++ b/polygerrit-ui/app/utils/message-util.ts
@@ -0,0 +1,32 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {MessageTag} from '../constants/constants';
+import {ChangeMessageInfo} from '../types/common';
+
+export function getRevertCommitHash(messages?: ChangeMessageInfo[]) {
+ const msg = messages?.find(m => m.tag === MessageTag.TAG_REVERT);
+ if (!msg) return undefined;
+ const REVERT_REGEX = /^Created a revert of this change as (.*)$/;
+ const commit = msg.message.match(REVERT_REGEX)?.[1];
+ if (!commit) throw new Error('revert commit not found');
+ return commit;
+}
+
+export function isRevertCreated(messages?: ChangeMessageInfo[]) {
+ return messages?.some(m => m.tag === MessageTag.TAG_REVERT);
+}
diff --git a/polygerrit-ui/app/utils/patch-set-util.ts b/polygerrit-ui/app/utils/patch-set-util.ts
index af56798..138479c 100644
--- a/polygerrit-ui/app/utils/patch-set-util.ts
+++ b/polygerrit-ui/app/utils/patch-set-util.ts
@@ -5,6 +5,8 @@
EditPatchSetNum,
ParentPatchSetNum,
PatchSetNumber,
+ BasePatchSetNum,
+ RevisionPatchSetNum,
} from '../types/common';
import {RestApiService} from '../services/gr-rest-api/gr-rest-api';
import {EditRevisionInfo, ParsedChangeInfo} from '../types/types';
@@ -47,7 +49,7 @@
interface PatchRange {
patchNum?: PatchSetNum;
- basePatchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
}
/**
@@ -106,6 +108,16 @@
return;
}
+export function getShaByPatchNum(
+ revisions: {[revisionId: string]: RevisionInfo | EditRevisionInfo},
+ patchNum: RevisionPatchSetNum
+) {
+ for (const [sha, rev] of Object.entries(revisions)) {
+ if (rev._number === patchNum) return sha;
+ }
+ return undefined;
+}
+
/**
* Find change edit base revision if change edit exists.
*
@@ -263,7 +275,7 @@
export function computePredecessor(
patchset?: PatchSetNum
-): PatchSetNum | undefined {
+): BasePatchSetNum | undefined {
if (
!patchset ||
patchset === ParentPatchSetNum ||
@@ -272,7 +284,7 @@
return undefined;
}
if (patchset === 1) return ParentPatchSetNum;
- return (Number(patchset) - 1) as PatchSetNum;
+ return (Number(patchset) - 1) as BasePatchSetNum;
}
export function hasEditBasedOnCurrentPatchSet(allPatchSets: PatchSet[]) {
diff --git a/polygerrit-ui/app/utils/string-util.ts b/polygerrit-ui/app/utils/string-util.ts
index 1b400cf..6aae67f 100644
--- a/polygerrit-ui/app/utils/string-util.ts
+++ b/polygerrit-ui/app/utils/string-util.ts
@@ -26,3 +26,7 @@
export function addQuotesWhen(string: string, cond: boolean): string {
return cond ? `"${string}"` : string;
}
+
+export function charsOnly(s: string): string {
+ return s.replace(/[^a-zA-Z]+/g, '');
+}
diff --git a/polygerrit-ui/app/utils/string-util_test.ts b/polygerrit-ui/app/utils/string-util_test.ts
index 9297d90..2eef50f 100644
--- a/polygerrit-ui/app/utils/string-util_test.ts
+++ b/polygerrit-ui/app/utils/string-util_test.ts
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-import '../test/common-test-setup-karma.js';
-import {pluralize} from './string-util.js';
+import '../test/common-test-setup-karma';
+import {pluralize} from './string-util';
suite('formatter util tests', () => {
test('pluralize', () => {
diff --git a/polygerrit-ui/app/utils/url-util.ts b/polygerrit-ui/app/utils/url-util.ts
index f977ab6..4115062 100644
--- a/polygerrit-ui/app/utils/url-util.ts
+++ b/polygerrit-ui/app/utils/url-util.ts
@@ -78,3 +78,33 @@
const withoutPlus = url.replace(/\+/g, '%20');
return decodeURIComponent(withoutPlus);
}
+
+/**
+ * @param path URL path including search params, but without host
+ */
+export function toPathname(path: string) {
+ const i = path.indexOf('?');
+ const hasQuery = i > -1;
+ const pathname = hasQuery ? path.slice(0, i) : path;
+ return pathname;
+}
+
+/**
+ * @param path URL path including search params, but without host
+ */
+export function toSearchParams(path: string) {
+ const i = path.indexOf('?');
+ const hasQuery = i > -1;
+ const querystring = hasQuery ? path.slice(i + 1) : '';
+ return new URLSearchParams(querystring);
+}
+
+/**
+ * @param pathname URL path without search params
+ * @param params
+ */
+export function toPath(pathname: string, searchParams: URLSearchParams) {
+ const paramString = searchParams.toString();
+ const middle = paramString ? '?' : '';
+ return pathname + middle + paramString;
+}
diff --git a/polygerrit-ui/app/utils/url-util_test.js b/polygerrit-ui/app/utils/url-util_test.js
index b1b17f4..5cd4bb4 100644
--- a/polygerrit-ui/app/utils/url-util_test.js
+++ b/polygerrit-ui/app/utils/url-util_test.js
@@ -20,7 +20,11 @@
getBaseUrl,
getDocsBaseUrl,
_testOnly_clearDocsBaseUrlCache,
- encodeURL, singleDecodeURL,
+ encodeURL,
+ singleDecodeURL,
+ toPath,
+ toPathname,
+ toSearchParams,
} from './url-util.js';
suite('url-util tests', () => {
@@ -124,4 +128,23 @@
});
});
});
+
+ test('toPathname', () => {
+ assert.equal(toPathname('asdf'), 'asdf');
+ assert.equal(toPathname('asdf?qwer=zxcv'), 'asdf');
+ });
+
+ test('toSearchParams', () => {
+ assert.equal(toSearchParams('asdf').toString(), '');
+ assert.equal(toSearchParams('asdf?qwer=zxcv').get('qwer'), 'zxcv');
+ });
+
+ test('toPathname', () => {
+ const params = new URLSearchParams();
+ assert.equal(toPath('asdf', params), 'asdf');
+ params.set('qwer', 'zxcv');
+ assert.equal(toPath('asdf', params), 'asdf?qwer=zxcv');
+ assert.equal(toPath(toPathname('asdf?qwer=zxcv'),
+ toSearchParams('asdf?qwer=zxcv')), 'asdf?qwer=zxcv');
+ });
});
diff --git a/polygerrit-ui/app/yarn.lock b/polygerrit-ui/app/yarn.lock
index ec3b7a0..77d3972 100644
--- a/polygerrit-ui/app/yarn.lock
+++ b/polygerrit-ui/app/yarn.lock
@@ -19,7 +19,7 @@
resolved "https://registry.yarnpkg.com/@polymer/font-roboto/-/font-roboto-3.0.2.tgz#80cdaa7225db2359130dfb2c6d9a3be1820020c3"
integrity sha512-tx5TauYSmzsIvmSqepUPDYbs4/Ejz2XbZ1IkD7JEGqkdNUJlh+9KU85G56Tfdk/xjEZ8zorFfN09OSwiMrIQWA==
-"@polymer/iron-a11y-announcer@^3.0.0-pre.26", "@polymer/iron-a11y-announcer@^3.0.1":
+"@polymer/iron-a11y-announcer@^3.0.0-pre.26", "@polymer/iron-a11y-announcer@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@polymer/iron-a11y-announcer/-/iron-a11y-announcer-3.1.0.tgz#3d3712a165070ed3cdfc39e54f95515c913c9613"
integrity sha512-lc5i4NKB8kSQHH0Hwu8WS3ym93m+J69OHJWSSBxwd17FI+h2wmgxDzeG9LI4ojMMck17/uc2pLe7g/UHt5/K/A==
@@ -60,7 +60,7 @@
"@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
-"@polymer/iron-dropdown@^3.0.1":
+"@polymer/iron-dropdown@^3.0.0-pre.26", "@polymer/iron-dropdown@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@polymer/iron-dropdown/-/iron-dropdown-3.0.1.tgz#c573faa1a08c179d201ae877c1c726018314bff3"
integrity sha512-22yLhepfcKjuQMfFmRHi/9MPKTqkzgRrmWWW0P5uqK++xle53k2QBO5VYUAYiCN3ZcxIi9lEhZ9YWGeQj2JBig==
@@ -70,10 +70,10 @@
"@polymer/neon-animation" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
-"@polymer/iron-fit-behavior@^3.0.0-pre.26", "@polymer/iron-fit-behavior@^3.0.2":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@polymer/iron-fit-behavior/-/iron-fit-behavior-3.0.2.tgz#2ec460d8a6b0151394b55631a72a68b92e14e2e0"
- integrity sha512-JndryJYbBR3gSN5IlST4rCHsd01+OyvYpRO6z5Zd3C6u5V/m07TwAtcf3aXwZ8WBNt2eLG28OcvdSO7XR2v2pg==
+"@polymer/iron-fit-behavior@^3.0.0-pre.26", "@polymer/iron-fit-behavior@^3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@polymer/iron-fit-behavior/-/iron-fit-behavior-3.1.0.tgz#8197a61e0ce2234e9bf8fbd7a1ae53d1a06026b0"
+ integrity sha512-ABcgIYqrjhmUT8tiuolqeGttF/8pd3sEymUDrO1vXbZu4FWIvoLNndrMDFvs++AGd12Mjf5pYy84NJc6dB8Vig==
dependencies:
"@polymer/polymer" "^3.0.0"
@@ -108,6 +108,13 @@
"@polymer/iron-meta" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
+"@polymer/iron-image@^3.0.0-pre.26":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@polymer/iron-image/-/iron-image-3.0.2.tgz#425ee6269634e024dbea726a91a61724ae4402b6"
+ integrity sha512-VyYtnewGozDb5sUeoLR1OvKzlt5WAL6b8Od7fPpio5oYL+9t061/nTV8+ZMrpMgF2WgB0zqM/3K53o3pbK5v8Q==
+ dependencies:
+ "@polymer/polymer" "^3.0.0"
+
"@polymer/iron-input@^3.0.0-pre.26", "@polymer/iron-input@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@polymer/iron-input/-/iron-input-3.0.1.tgz#dc866a25107f9b38d9ca4512dd9a3e51b78b4915"
@@ -195,6 +202,28 @@
"@polymer/paper-styles" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
+"@polymer/paper-card@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@polymer/paper-card/-/paper-card-3.0.1.tgz#fb5960b3e55fab56d20b7c1c3dee08f0d052ff2a"
+ integrity sha512-ZYzfA4kzP9niRO22wSOBL2RS+URZNUP5XmUCwN91fYPIGO0Qbimh7d1O2HpJD4cRCZhvGYn2CJMDMVmDm35vIg==
+ dependencies:
+ "@polymer/iron-flex-layout" "^3.0.0-pre.26"
+ "@polymer/iron-image" "^3.0.0-pre.26"
+ "@polymer/paper-styles" "^3.0.0-pre.26"
+ "@polymer/polymer" "^3.0.0"
+
+"@polymer/paper-checkbox@^3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@polymer/paper-checkbox/-/paper-checkbox-3.1.0.tgz#66b903ae5814db237d027deb4a3f3430f48d905b"
+ integrity sha512-kXm6yDG1tT8if0XuJ2cc9NF+g8Ev4wG+rnf0a+Sx+O7J6fn1jcnBlYn72FlrfjVjDQZDBFmT6nynhD5PvFw8iQ==
+ dependencies:
+ "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+ "@polymer/iron-checked-element-behavior" "^3.0.0-pre.26"
+ "@polymer/paper-behaviors" "^3.0.0-pre.27"
+ "@polymer/paper-ripple" "^3.0.0-pre.26"
+ "@polymer/paper-styles" "^3.0.0-pre.26"
+ "@polymer/polymer" "^3.0.0"
+
"@polymer/paper-dialog-behavior@^3.0.0-pre.26", "@polymer/paper-dialog-behavior@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@polymer/paper-dialog-behavior/-/paper-dialog-behavior-3.0.1.tgz#819b2fbb9444c1c318ddf55f02819bb29a85657b"
@@ -224,6 +253,23 @@
"@polymer/paper-dialog-behavior" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
+"@polymer/paper-dropdown-menu@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@polymer/paper-dropdown-menu/-/paper-dropdown-menu-3.2.0.tgz#17f507ef864dc18365a92e256bde628c2d352956"
+ integrity sha512-2ohwSHF+RLSK6kA0UkkMiMQF6EZcaEYWAA25kfisI6DWie7yozKrpQNsqvwfOEHU6DdDMIotrOtH1TM88YS8Zg==
+ dependencies:
+ "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+ "@polymer/iron-form-element-behavior" "^3.0.0-pre.26"
+ "@polymer/iron-icon" "^3.0.0-pre.26"
+ "@polymer/iron-iconset-svg" "^3.0.0-pre.26"
+ "@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
+ "@polymer/paper-behaviors" "^3.0.0-pre.27"
+ "@polymer/paper-input" "^3.1.0"
+ "@polymer/paper-menu-button" "^3.1.0"
+ "@polymer/paper-ripple" "^3.0.0-pre.26"
+ "@polymer/paper-styles" "^3.0.0-pre.26"
+ "@polymer/polymer" "^3.3.1"
+
"@polymer/paper-icon-button@^3.0.0-pre.26":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@polymer/paper-icon-button/-/paper-icon-button-3.0.2.tgz#a1254faadc2c8dd135ce1ae33bcc161a94c31f65"
@@ -234,7 +280,7 @@
"@polymer/paper-styles" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
-"@polymer/paper-input@^3.2.1":
+"@polymer/paper-input@^3.1.0", "@polymer/paper-input@^3.2.1":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@polymer/paper-input/-/paper-input-3.2.1.tgz#0fd0d30de3b43ba7d2c8d5d76f870d257b667ebf"
integrity sha512-6ghgwQKM6mS0hAQxQqj+tkeEY1VUBqAsrasAm8V5RpNcfSWQC/hhRFxU0beGuKTAhndzezDzWYP6Zz4b8fExGg==
@@ -267,6 +313,19 @@
"@polymer/paper-styles" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
+"@polymer/paper-menu-button@^3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@polymer/paper-menu-button/-/paper-menu-button-3.1.0.tgz#3eb2fb88ba3cdaa4c39be6ae3530efa40b1eccf3"
+ integrity sha512-q0G0/rvYD/FFmIBMGCQWjfXzRqwFw9+WHSYV4uOQzM1Ln8LMXSAd+2CENsbVwtMh6fmBePj15ZlU8SM2dt1WDQ==
+ dependencies:
+ "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
+ "@polymer/iron-behaviors" "^3.0.0-pre.26"
+ "@polymer/iron-dropdown" "^3.0.0-pre.26"
+ "@polymer/iron-fit-behavior" "^3.1.0"
+ "@polymer/neon-animation" "^3.0.0-pre.26"
+ "@polymer/paper-styles" "^3.0.0-pre.26"
+ "@polymer/polymer" "^3.0.0"
+
"@polymer/paper-ripple@^3.0.0-pre.26":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@polymer/paper-ripple/-/paper-ripple-3.0.2.tgz#52566f5ee367942022ceaa991368105d21403de5"
@@ -275,7 +334,7 @@
"@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
-"@polymer/paper-styles@^3.0.0-pre.26":
+"@polymer/paper-styles@^3.0.0-pre.26", "@polymer/paper-styles@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@polymer/paper-styles/-/paper-styles-3.0.1.tgz#bd4962b83ab8432cd1cf197bb5222d3a08f135e1"
integrity sha512-y6hmObLqlCx602TQiSBKHqjwkE7xmDiFkoxdYGaNjtv4xcysOTdVJsDR/R9UHwIaxJ7gHlthMSykir1nv78++g==
@@ -310,29 +369,30 @@
"@polymer/paper-styles" "^3.0.0-pre.26"
"@polymer/polymer" "^3.0.0"
-"@polymer/polymer@^3.0.0", "@polymer/polymer@^3.0.5", "@polymer/polymer@^3.4.1":
+"@polymer/paper-tooltip@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@polymer/paper-tooltip/-/paper-tooltip-3.0.1.tgz#cdbb06442737513f081437c6302842170ce714dc"
+ integrity sha512-yiUk09opTEnE1lK+tb501ENb+yQBi4p++Ep0eGJAHesVYKVMPNgPphVKkIizkDaU+n0SE+zXfTsRbYyOMDYXSg==
+ dependencies:
+ "@polymer/paper-styles" "^3.0.0-pre.26"
+ "@polymer/polymer" "^3.0.0"
+
+"@polymer/polymer@^3.0.0", "@polymer/polymer@^3.0.2", "@polymer/polymer@^3.0.5", "@polymer/polymer@^3.3.1", "@polymer/polymer@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.4.1.tgz#333bef25711f8411bb5624fb3eba8212ef8bee96"
integrity sha512-KPWnhDZibtqKrUz7enIPOiO4ZQoJNOuLwqrhV2MXzIt3VVnUVJVG5ORz4Z2sgO+UZ+/UZnPD0jqY+jmw/+a9mQ==
dependencies:
"@webcomponents/shadycss" "^1.9.1"
-"@polymer/polymer@^3.0.2":
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
- integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
- dependencies:
- "@webcomponents/shadycss" "^1.9.1"
-
"@types/resize-observer-browser@^0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz#36d897708172ac2380cd486da7a3daf1161c1e23"
integrity sha512-8k/67Z95Goa6Lznuykxkfhq9YU3l1Qe6LNZmwde1u7802a3x8v44oq0j91DICclxatTr0rNnhXx7+VTIetSrSQ==
-"@webcomponents/shadycss@^1.9.1", "@webcomponents/shadycss@^1.9.2":
- version "1.9.4"
- resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
- integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+"@webcomponents/shadycss@^1.10.2", "@webcomponents/shadycss@^1.9.1":
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.2.tgz#40e03cab6dc5e12f199949ba2b79e02f183d1e7b"
+ integrity sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==
"@webcomponents/webcomponentsjs@^1.3.3":
version "1.3.3"
@@ -340,9 +400,9 @@
integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
"@webcomponents/webcomponentsjs@^2.0.3":
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.1.tgz#7baadec56ed2fd79b94ddfd509132d8c0c295c5c"
- integrity sha512-7jxBb+KoWncKb/JGFyTY40PjV4yRx2zd35ZLuvRP+6WndJDL7X32ZIZ7bN3sSQIl+NzJkCo7chfXJyzn+6WZaQ==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.5.0.tgz#61b27785a6ad5bfd68fa018201fe418b118cb38d"
+ integrity sha512-C0l51MWQZ9kLzcxOZtniOMohpIFdCLZum7/TEHv3XWFc1Fvt5HCpbSX84x8ltka/JuNKcuiDnxXFkiB2gaePcg==
"ba-linkify@file:../../lib/ba-linkify/src":
version "1.0.0"
@@ -364,10 +424,10 @@
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.3.0.tgz#c80f3cc5793a6dea6c07172be90a70ab20e56034"
integrity sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q==
-page@^1.11.5:
- version "1.11.5"
- resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
- integrity sha512-0JXUHc7Y8p1cPJQbhZSwaKO3p+bU3Rgny+OM5gJMKHWHvJKan/fsE5RUzEjRQolv9DzPOSVWfSOHz0lLxK19eA==
+page@^1.11.6:
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/page/-/page-1.11.6.tgz#5ef4efc7073749b8085ccdaa0dcd7c9e0de12fe3"
+ integrity sha512-P6e2JfzkBrPeFCIPplLP7vDDiU84RUUZMrWdsH4ZBGJ8OosnwFkcUkBHp1DTIjuipLliw9yQn/ZJsXZvarsO+g==
dependencies:
path-to-regexp "~1.2.1"
@@ -389,10 +449,10 @@
"@polymer/polymer" "^3.0.2"
"@webcomponents/webcomponentsjs" "^2.0.3"
-rxjs@^6.6.2:
- version "6.6.2"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2"
- integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==
+rxjs@^6.6.7:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
+ integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
@@ -402,6 +462,6 @@
integrity sha512-ntz8P6DLEFpx7gikeXZ4gSi3APE2D+BP0rKnnaBzED+Lm8je8nkNcayy6kGWPEDWMFbtm+Yvd1ONFaXcsVWn2w==
tslib@^1.9.0:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
- integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
diff --git a/polygerrit-ui/package.json b/polygerrit-ui/package.json
index c01ef56..3aa0c92 100644
--- a/polygerrit-ui/package.json
+++ b/polygerrit-ui/package.json
@@ -3,24 +3,24 @@
"description": "Gerrit Code Review - Polygerrit dev dependencies",
"browser": true,
"dependencies": {
- "@types/chai": "^4.2.14",
- "@types/lodash": "^4.14.162",
- "@types/mocha": "^8.0.3",
- "@types/sinon": "^9.0.8"
+ "@types/chai": "^4.2.16",
+ "@types/lodash": "^4.14.168",
+ "@types/mocha": "^8.2.2",
+ "@types/sinon": "^10.0.0"
},
"devDependencies": {
"@open-wc/karma-esm": "^2.16.16",
"@polymer/iron-test-helpers": "^3.0.1",
"@polymer/test-fixture": "^4.0.2",
"accessibility-developer-tools": "^2.12.0",
- "chai": "^4.2.0",
+ "chai": "^4.3.4",
"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.2.0",
- "sinon": "^9.0.2",
+ "lodash": "^4.17.21",
+ "mocha": "8.3.2",
+ "sinon": "^10.0.0",
"source-map-support": "^0.5.19"
},
"license": "Apache-2.0",
diff --git a/polygerrit-ui/server.go b/polygerrit-ui/server.go
index e6487a7..2734f58 100644
--- a/polygerrit-ui/server.go
+++ b/polygerrit-ui/server.go
@@ -400,14 +400,8 @@
insertionPoint := strings.Index(replaced, "</script>")
builder := new(strings.Builder)
builder.WriteString(
- "window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths = []; ")
- builder.WriteString(
"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths = []; ")
for _, p := range strings.Split(*plugins, ",") {
- if filepath.Ext(p) == ".html" {
- builder.WriteString(
- "window.INITIAL_DATA['/config/server/info'].plugin.html_resource_paths.push('" + p + "'); ")
- }
if filepath.Ext(p) == ".js" {
builder.WriteString(
"window.INITIAL_DATA['/config/server/info'].plugin.js_resource_paths.push('" + p + "'); ")
@@ -435,22 +429,15 @@
// Configuration path in the JSON server response
jsPluginsPath := []string{"plugin", "js_resource_paths"}
- htmlPluginsPath := []string{"plugin", "html_resource_paths"}
- htmlResources := getJsonPropByPath(response, htmlPluginsPath).([]interface{})
jsResources := getJsonPropByPath(response, jsPluginsPath).([]interface{})
for _, p := range strings.Split(*plugins, ",") {
- if filepath.Ext(p) == ".html" {
- htmlResources = append(htmlResources, p)
- }
-
if filepath.Ext(p) == ".js" {
jsResources = append(jsResources, p)
}
}
setJsonPropByPath(response, jsPluginsPath, jsResources)
- setJsonPropByPath(response, htmlPluginsPath, htmlResources)
reader, writer := io.Pipe()
go func() {
diff --git a/polygerrit-ui/yarn.lock b/polygerrit-ui/yarn.lock
index 2acd478..271b295 100644
--- a/polygerrit-ui/yarn.lock
+++ b/polygerrit-ui/yarn.lock
@@ -2,387 +2,428 @@
# yarn lockfile v1
-"@babel/code-frame@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
- integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+"@babel/code-frame@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
+ integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
dependencies:
- "@babel/highlight" "^7.10.4"
+ "@babel/highlight" "^7.12.13"
-"@babel/compat-data@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.4.tgz#706a6484ee6f910b719b696a9194f8da7d7ac241"
- integrity sha512-t+rjExOrSVvjQQXNp5zAIYDp00KjdvGl/TpDX5REPr0S9IAIPQMTilcfG6q8c0QFmj9lSTVySV2VTsyggvtNIw==
- dependencies:
- browserslist "^4.12.0"
- invariant "^2.2.4"
- semver "^5.5.0"
+"@babel/compat-data@^7.13.0", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.12.tgz#a8a5ccac19c200f9dd49624cac6e19d7be1236a1"
+ integrity sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==
-"@babel/core@^7.9.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.4.tgz#780e8b83e496152f8dd7df63892b2e052bf1d51d"
- integrity sha512-3A0tS0HWpy4XujGc7QtOIHTeNwUgWaZc/WuS5YQrfhU67jnVmsD6OGPc1AKHH0LJHQICGncy3+YUjIhVlfDdcA==
+"@babel/core@^7.11.1":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.14.tgz#8e46ebbaca460a63497c797e574038ab04ae6d06"
+ integrity sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==
dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.10.4"
- "@babel/helper-module-transforms" "^7.10.4"
- "@babel/helpers" "^7.10.4"
- "@babel/parser" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/code-frame" "^7.12.13"
+ "@babel/generator" "^7.13.9"
+ "@babel/helper-compilation-targets" "^7.13.13"
+ "@babel/helper-module-transforms" "^7.13.14"
+ "@babel/helpers" "^7.13.10"
+ "@babel/parser" "^7.13.13"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.13"
+ "@babel/types" "^7.13.14"
convert-source-map "^1.7.0"
debug "^4.1.0"
- gensync "^1.0.0-beta.1"
+ gensync "^1.0.0-beta.2"
json5 "^2.1.2"
- lodash "^4.17.13"
- resolve "^1.3.2"
- semver "^5.4.1"
+ semver "^6.3.0"
source-map "^0.5.0"
-"@babel/generator@^7.10.4", "@babel/generator@^7.4.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243"
- integrity sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==
+"@babel/generator@^7.13.9", "@babel/generator@^7.4.0":
+ version "7.13.9"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
+ integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.13.0"
jsesc "^2.5.1"
- lodash "^4.17.13"
source-map "^0.5.0"
-"@babel/helper-annotate-as-pure@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
- integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
+"@babel/helper-annotate-as-pure@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
+ integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.12.13"
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
- integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc"
+ integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==
dependencies:
- "@babel/helper-explode-assignable-expression" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/helper-explode-assignable-expression" "^7.12.13"
+ "@babel/types" "^7.12.13"
-"@babel/helper-compilation-targets@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
- integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==
+"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8":
+ version "7.13.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5"
+ integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==
dependencies:
- "@babel/compat-data" "^7.10.4"
- browserslist "^4.12.0"
- invariant "^2.2.4"
- levenary "^1.1.1"
- semver "^5.5.0"
+ "@babel/compat-data" "^7.13.12"
+ "@babel/helper-validator-option" "^7.12.17"
+ browserslist "^4.14.5"
+ semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz#2d4015d0136bd314103a70d84a7183e4b344a355"
- integrity sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ==
+"@babel/helper-create-class-features-plugin@^7.13.0":
+ version "7.13.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz#30d30a005bca2c953f5653fc25091a492177f4f6"
+ integrity sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==
dependencies:
- "@babel/helper-function-name" "^7.10.4"
- "@babel/helper-member-expression-to-functions" "^7.10.4"
- "@babel/helper-optimise-call-expression" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-replace-supers" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.10.4"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-member-expression-to-functions" "^7.13.0"
+ "@babel/helper-optimise-call-expression" "^7.12.13"
+ "@babel/helper-replace-supers" "^7.13.0"
+ "@babel/helper-split-export-declaration" "^7.12.13"
-"@babel/helper-create-regexp-features-plugin@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
- integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==
+"@babel/helper-create-regexp-features-plugin@^7.12.13":
+ version "7.12.17"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7"
+ integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.10.4"
- "@babel/helper-regex" "^7.10.4"
- regexpu-core "^4.7.0"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ regexpu-core "^4.7.1"
-"@babel/helper-define-map@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz#f037ad794264f729eda1889f4ee210b870999092"
- integrity sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA==
+"@babel/helper-define-polyfill-provider@^0.1.5":
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz#3c2f91b7971b9fc11fe779c945c014065dea340e"
+ integrity sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==
dependencies:
- "@babel/helper-function-name" "^7.10.4"
- "@babel/types" "^7.10.4"
- lodash "^4.17.13"
+ "@babel/helper-compilation-targets" "^7.13.0"
+ "@babel/helper-module-imports" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/traverse" "^7.13.0"
+ debug "^4.1.1"
+ lodash.debounce "^4.0.8"
+ resolve "^1.14.2"
+ semver "^6.1.2"
-"@babel/helper-explode-assignable-expression@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c"
- integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==
+"@babel/helper-explode-assignable-expression@^7.12.13":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f"
+ integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==
dependencies:
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.13.0"
-"@babel/helper-function-name@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
- integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
+"@babel/helper-function-name@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a"
+ integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==
dependencies:
- "@babel/helper-get-function-arity" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/helper-get-function-arity" "^7.12.13"
+ "@babel/template" "^7.12.13"
+ "@babel/types" "^7.12.13"
-"@babel/helper-get-function-arity@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
- integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
+"@babel/helper-get-function-arity@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
+ integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.12.13"
-"@babel/helper-hoist-variables@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e"
- integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==
+"@babel/helper-hoist-variables@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz#5d5882e855b5c5eda91e0cadc26c6e7a2c8593d8"
+ integrity sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/helper-member-expression-to-functions@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz#7cd04b57dfcf82fce9aeae7d4e4452fa31b8c7c4"
- integrity sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A==
+"@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
+ integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.13.12"
-"@babel/helper-module-imports@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
- integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
+"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
+ integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.13.12"
-"@babel/helper-module-transforms@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz#ca1f01fdb84e48c24d7506bb818c961f1da8805d"
- integrity sha512-Er2FQX0oa3nV7eM1o0tNCTx7izmQtwAQsIiaLRWtavAAEcskb0XJ5OjJbVrYXWOTr8om921Scabn4/tzlx7j1Q==
+"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef"
+ integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==
dependencies:
- "@babel/helper-module-imports" "^7.10.4"
- "@babel/helper-replace-supers" "^7.10.4"
- "@babel/helper-simple-access" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.10.4"
- lodash "^4.17.13"
+ "@babel/helper-module-imports" "^7.13.12"
+ "@babel/helper-replace-supers" "^7.13.12"
+ "@babel/helper-simple-access" "^7.13.12"
+ "@babel/helper-split-export-declaration" "^7.12.13"
+ "@babel/helper-validator-identifier" "^7.12.11"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.13"
+ "@babel/types" "^7.13.14"
-"@babel/helper-optimise-call-expression@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
- integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
+"@babel/helper-optimise-call-expression@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea"
+ integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.12.13"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
- integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
+ integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
-"@babel/helper-regex@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.4.tgz#59b373daaf3458e5747dece71bbaf45f9676af6d"
- integrity sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ==
+"@babel/helper-remap-async-to-generator@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
+ integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==
dependencies:
- lodash "^4.17.13"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ "@babel/helper-wrap-function" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/helper-remap-async-to-generator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5"
- integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==
+"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804"
+ integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.10.4"
- "@babel/helper-wrap-function" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/helper-member-expression-to-functions" "^7.13.12"
+ "@babel/helper-optimise-call-expression" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.12"
-"@babel/helper-replace-supers@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
- integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
+"@babel/helper-simple-access@^7.12.13", "@babel/helper-simple-access@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6"
+ integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==
dependencies:
- "@babel/helper-member-expression-to-functions" "^7.10.4"
- "@babel/helper-optimise-call-expression" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.13.12"
-"@babel/helper-simple-access@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
- integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==
+"@babel/helper-skip-transparent-expression-wrappers@^7.12.1":
+ version "7.12.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf"
+ integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==
dependencies:
- "@babel/template" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.12.1"
-"@babel/helper-split-export-declaration@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1"
- integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==
+"@babel/helper-split-export-declaration@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05"
+ integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==
dependencies:
- "@babel/types" "^7.10.4"
+ "@babel/types" "^7.12.13"
-"@babel/helper-validator-identifier@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
- integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
+"@babel/helper-validator-identifier@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
+ integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
-"@babel/helper-wrap-function@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
- integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==
+"@babel/helper-validator-option@^7.12.17":
+ version "7.12.17"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831"
+ integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==
+
+"@babel/helper-wrap-function@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
+ integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==
dependencies:
- "@babel/helper-function-name" "^7.10.4"
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/helpers@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044"
- integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==
+"@babel/helpers@^7.13.10":
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
+ integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
dependencies:
- "@babel/template" "^7.10.4"
- "@babel/traverse" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/highlight@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
- integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
+"@babel/highlight@^7.12.13":
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1"
+ integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
dependencies:
- "@babel/helper-validator-identifier" "^7.10.4"
+ "@babel/helper-validator-identifier" "^7.12.11"
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.4.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64"
- integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==
+"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.13", "@babel/parser@^7.4.3":
+ version "7.13.13"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df"
+ integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
-"@babel/plugin-proposal-async-generator-functions@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz#4b65abb3d9bacc6c657aaa413e56696f9f170fc6"
- integrity sha512-MJbxGSmejEFVOANAezdO39SObkURO5o/8b6fSH6D1pi9RZQt+ldppKPXfqgUWpSQ9asM6xaSaSJIaeWMDRP0Zg==
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a"
+ integrity sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-remap-async-to-generator" "^7.10.4"
- "@babel/plugin-syntax-async-generators" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
+ "@babel/plugin-proposal-optional-chaining" "^7.13.12"
-"@babel/plugin-proposal-class-properties@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807"
- integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==
+"@babel/plugin-proposal-async-generator-functions@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz#87aacb574b3bc4b5603f6fe41458d72a5a2ec4b1"
+ integrity sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-remap-async-to-generator" "^7.13.0"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
-"@babel/plugin-proposal-dynamic-import@^7.10.4", "@babel/plugin-proposal-dynamic-import@^7.8.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e"
- integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==
+"@babel/plugin-proposal-class-properties@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37"
+ integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+ "@babel/helper-create-class-features-plugin" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-proposal-json-strings@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db"
- integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==
+"@babel/plugin-proposal-dynamic-import@^7.10.4", "@babel/plugin-proposal-dynamic-import@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz#876a1f6966e1dec332e8c9451afda3bebcdf2e1d"
+ integrity sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-json-strings" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a"
- integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==
+"@babel/plugin-proposal-export-namespace-from@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz#393be47a4acd03fa2af6e3cde9b06e33de1b446d"
+ integrity sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
-"@babel/plugin-proposal-numeric-separator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06"
- integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==
+"@babel/plugin-proposal-json-strings@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz#bf1fb362547075afda3634ed31571c5901afef7b"
+ integrity sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+
+"@babel/plugin-proposal-logical-assignment-operators@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz#93fa78d63857c40ce3c8c3315220fd00bfbb4e1a"
+ integrity sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz#3730a31dafd3c10d8ccd10648ed80a2ac5472ef3"
+ integrity sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+
+"@babel/plugin-proposal-numeric-separator@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz#bd9da3188e787b5120b4f9d465a8261ce67ed1db"
+ integrity sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-syntax-numeric-separator" "^7.10.4"
-"@babel/plugin-proposal-object-rest-spread@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0"
- integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA==
+"@babel/plugin-proposal-object-rest-spread@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a"
+ integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
- "@babel/plugin-transform-parameters" "^7.10.4"
+ "@babel/compat-data" "^7.13.8"
+ "@babel/helper-compilation-targets" "^7.13.8"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.13.0"
-"@babel/plugin-proposal-optional-catch-binding@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd"
- integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==
+"@babel/plugin-proposal-optional-catch-binding@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz#3ad6bd5901506ea996fc31bdcf3ccfa2bed71107"
+ integrity sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
-"@babel/plugin-proposal-optional-chaining@^7.10.4", "@babel/plugin-proposal-optional-chaining@^7.9.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz#750f1255e930a1f82d8cdde45031f81a0d0adff7"
- integrity sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ==
+"@babel/plugin-proposal-optional-chaining@^7.11.0", "@babel/plugin-proposal-optional-chaining@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz#ba9feb601d422e0adea6760c2bd6bbb7bfec4866"
+ integrity sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
-"@babel/plugin-proposal-private-methods@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909"
- integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==
+"@babel/plugin-proposal-private-methods@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787"
+ integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==
dependencies:
- "@babel/helper-create-class-features-plugin" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-create-class-features-plugin" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d"
- integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==
+"@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba"
+ integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-syntax-async-generators@^7.8.0":
+"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-class-properties@^7.10.4", "@babel/plugin-syntax-class-properties@^7.8.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c"
- integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==
+"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
+ integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3":
+"@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.8.3":
+"@babel/plugin-syntax-export-namespace-from@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a"
+ integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-import-meta@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-syntax-json-strings@^7.8.0":
+"@babel/plugin-syntax-json-strings@^7.8.3":
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":
+"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
+ integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@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==
@@ -396,359 +437,361 @@
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-syntax-object-rest-spread@^7.8.0":
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
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"
integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
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":
+"@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.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d"
- integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==
+"@babel/plugin-syntax-top-level-await@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178"
+ integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-arrow-functions@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd"
- integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==
+"@babel/plugin-transform-arrow-functions@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae"
+ integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-async-to-generator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37"
- integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==
+"@babel/plugin-transform-async-to-generator@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f"
+ integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==
dependencies:
- "@babel/helper-module-imports" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-remap-async-to-generator" "^7.10.4"
+ "@babel/helper-module-imports" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-remap-async-to-generator" "^7.13.0"
-"@babel/plugin-transform-block-scoped-functions@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8"
- integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==
+"@babel/plugin-transform-block-scoped-functions@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4"
+ integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-block-scoping@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.4.tgz#a670d1364bb5019a621b9ea2001482876d734787"
- integrity sha512-J3b5CluMg3hPUii2onJDRiaVbPtKFPLEaV5dOPY5OeAbDi1iU/UbbFFTgwb7WnanaDy7bjU35kc26W3eM5Qa0A==
+"@babel/plugin-transform-block-scoping@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61"
+ integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- lodash "^4.17.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-classes@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7"
- integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==
+"@babel/plugin-transform-classes@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz#0265155075c42918bf4d3a4053134176ad9b533b"
+ integrity sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.10.4"
- "@babel/helper-define-map" "^7.10.4"
- "@babel/helper-function-name" "^7.10.4"
- "@babel/helper-optimise-call-expression" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-replace-supers" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.10.4"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-optimise-call-expression" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-replace-supers" "^7.13.0"
+ "@babel/helper-split-export-declaration" "^7.12.13"
globals "^11.1.0"
-"@babel/plugin-transform-computed-properties@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb"
- integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==
+"@babel/plugin-transform-computed-properties@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed"
+ integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-destructuring@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5"
- integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==
+"@babel/plugin-transform-destructuring@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963"
+ integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee"
- integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==
+"@babel/plugin-transform-dotall-regex@^7.12.13", "@babel/plugin-transform-dotall-regex@^7.4.4":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad"
+ integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-duplicate-keys@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47"
- integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==
+"@babel/plugin-transform-duplicate-keys@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de"
+ integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-exponentiation-operator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e"
- integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==
+"@babel/plugin-transform-exponentiation-operator@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1"
+ integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==
dependencies:
- "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-for-of@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9"
- integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==
+"@babel/plugin-transform-for-of@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062"
+ integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-function-name@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7"
- integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==
+"@babel/plugin-transform-function-name@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051"
+ integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==
dependencies:
- "@babel/helper-function-name" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-literals@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c"
- integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==
+"@babel/plugin-transform-literals@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9"
+ integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-member-expression-literals@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7"
- integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==
+"@babel/plugin-transform-member-expression-literals@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40"
+ integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-modules-amd@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.4.tgz#cb407c68b862e4c1d13a2fc738c7ec5ed75fc520"
- integrity sha512-3Fw+H3WLUrTlzi3zMiZWp3AR4xadAEMv6XRCYnd5jAlLM61Rn+CRJaZMaNvIpcJpQ3vs1kyifYvEVPFfoSkKOA==
+"@babel/plugin-transform-modules-amd@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3"
+ integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==
dependencies:
- "@babel/helper-module-transforms" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-module-transforms" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-commonjs@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0"
- integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==
+"@babel/plugin-transform-modules-commonjs@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz#7b01ad7c2dcf2275b06fa1781e00d13d420b3e1b"
+ integrity sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==
dependencies:
- "@babel/helper-module-transforms" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-simple-access" "^7.10.4"
+ "@babel/helper-module-transforms" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-simple-access" "^7.12.13"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-systemjs@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.4.tgz#8f576afd943ac2f789b35ded0a6312f929c633f9"
- integrity sha512-Tb28LlfxrTiOTGtZFsvkjpyjCl9IoaRI52AEU/VIwOwvDQWtbNJsAqTXzh+5R7i74e/OZHH2c2w2fsOqAfnQYQ==
+"@babel/plugin-transform-modules-systemjs@^7.13.8":
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3"
+ integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==
dependencies:
- "@babel/helper-hoist-variables" "^7.10.4"
- "@babel/helper-module-transforms" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-hoist-variables" "^7.13.0"
+ "@babel/helper-module-transforms" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-validator-identifier" "^7.12.11"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-modules-umd@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e"
- integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==
+"@babel/plugin-transform-modules-umd@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz#8a3d96a97d199705b9fd021580082af81c06e70b"
+ integrity sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==
dependencies:
- "@babel/helper-module-transforms" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-module-transforms" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6"
- integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9"
+ integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.10.4"
+ "@babel/helper-create-regexp-features-plugin" "^7.12.13"
-"@babel/plugin-transform-new-target@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888"
- integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==
+"@babel/plugin-transform-new-target@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c"
+ integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-object-super@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894"
- integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==
+"@babel/plugin-transform-object-super@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7"
+ integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-replace-supers" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
+ "@babel/helper-replace-supers" "^7.12.13"
-"@babel/plugin-transform-parameters@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.4.tgz#7b4d137c87ea7adc2a0f3ebf53266871daa6fced"
- integrity sha512-RurVtZ/D5nYfEg0iVERXYKEgDFeesHrHfx8RT05Sq57ucj2eOYAP6eu5fynL4Adju4I/mP/I6SO0DqNWAXjfLQ==
+"@babel/plugin-transform-parameters@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz#8fa7603e3097f9c0b7ca1a4821bc2fb52e9e5007"
+ integrity sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==
dependencies:
- "@babel/helper-get-function-arity" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-property-literals@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0"
- integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==
+"@babel/plugin-transform-property-literals@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81"
+ integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-regenerator@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63"
- integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==
+"@babel/plugin-transform-regenerator@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz#b628bcc9c85260ac1aeb05b45bde25210194a2f5"
+ integrity sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==
dependencies:
regenerator-transform "^0.14.2"
-"@babel/plugin-transform-reserved-words@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd"
- integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==
+"@babel/plugin-transform-reserved-words@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695"
+ integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-shorthand-properties@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6"
- integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==
+"@babel/plugin-transform-shorthand-properties@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad"
+ integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-spread@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff"
- integrity sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ==
+"@babel/plugin-transform-spread@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd"
+ integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
-"@babel/plugin-transform-sticky-regex@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d"
- integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==
+"@babel/plugin-transform-sticky-regex@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f"
+ integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-regex" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-template-literals@^7.10.4", "@babel/plugin-transform-template-literals@^7.8.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.4.tgz#e6375407b30fcb7fcfdbba3bb98ef3e9d36df7bc"
- integrity sha512-4NErciJkAYe+xI5cqfS8pV/0ntlY5N5Ske/4ImxAVX7mk9Rxt2bwDTGv1Msc2BRJvWQcmYEC+yoMLdX22aE4VQ==
+"@babel/plugin-transform-template-literals@^7.13.0", "@babel/plugin-transform-template-literals@^7.8.3":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d"
+ integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.13.0"
-"@babel/plugin-transform-typeof-symbol@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc"
- integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==
+"@babel/plugin-transform-typeof-symbol@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f"
+ integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-unicode-escapes@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007"
- integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==
+"@babel/plugin-transform-unicode-escapes@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74"
+ integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/plugin-transform-unicode-regex@^7.10.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8"
- integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==
+"@babel/plugin-transform-unicode-regex@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac"
+ integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/preset-env@^7.9.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f"
- integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw==
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.12.tgz#6dff470478290582ac282fb77780eadf32480237"
+ integrity sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==
dependencies:
- "@babel/compat-data" "^7.10.4"
- "@babel/helper-compilation-targets" "^7.10.4"
- "@babel/helper-module-imports" "^7.10.4"
- "@babel/helper-plugin-utils" "^7.10.4"
- "@babel/plugin-proposal-async-generator-functions" "^7.10.4"
- "@babel/plugin-proposal-class-properties" "^7.10.4"
- "@babel/plugin-proposal-dynamic-import" "^7.10.4"
- "@babel/plugin-proposal-json-strings" "^7.10.4"
- "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4"
- "@babel/plugin-proposal-numeric-separator" "^7.10.4"
- "@babel/plugin-proposal-object-rest-spread" "^7.10.4"
- "@babel/plugin-proposal-optional-catch-binding" "^7.10.4"
- "@babel/plugin-proposal-optional-chaining" "^7.10.4"
- "@babel/plugin-proposal-private-methods" "^7.10.4"
- "@babel/plugin-proposal-unicode-property-regex" "^7.10.4"
- "@babel/plugin-syntax-async-generators" "^7.8.0"
- "@babel/plugin-syntax-class-properties" "^7.10.4"
- "@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/compat-data" "^7.13.12"
+ "@babel/helper-compilation-targets" "^7.13.10"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-validator-option" "^7.12.17"
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12"
+ "@babel/plugin-proposal-async-generator-functions" "^7.13.8"
+ "@babel/plugin-proposal-class-properties" "^7.13.0"
+ "@babel/plugin-proposal-dynamic-import" "^7.13.8"
+ "@babel/plugin-proposal-export-namespace-from" "^7.12.13"
+ "@babel/plugin-proposal-json-strings" "^7.13.8"
+ "@babel/plugin-proposal-logical-assignment-operators" "^7.13.8"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8"
+ "@babel/plugin-proposal-numeric-separator" "^7.12.13"
+ "@babel/plugin-proposal-object-rest-spread" "^7.13.8"
+ "@babel/plugin-proposal-optional-catch-binding" "^7.13.8"
+ "@babel/plugin-proposal-optional-chaining" "^7.13.12"
+ "@babel/plugin-proposal-private-methods" "^7.13.0"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.12.13"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-class-properties" "^7.12.13"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
"@babel/plugin-syntax-numeric-separator" "^7.10.4"
- "@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.10.4"
- "@babel/plugin-transform-arrow-functions" "^7.10.4"
- "@babel/plugin-transform-async-to-generator" "^7.10.4"
- "@babel/plugin-transform-block-scoped-functions" "^7.10.4"
- "@babel/plugin-transform-block-scoping" "^7.10.4"
- "@babel/plugin-transform-classes" "^7.10.4"
- "@babel/plugin-transform-computed-properties" "^7.10.4"
- "@babel/plugin-transform-destructuring" "^7.10.4"
- "@babel/plugin-transform-dotall-regex" "^7.10.4"
- "@babel/plugin-transform-duplicate-keys" "^7.10.4"
- "@babel/plugin-transform-exponentiation-operator" "^7.10.4"
- "@babel/plugin-transform-for-of" "^7.10.4"
- "@babel/plugin-transform-function-name" "^7.10.4"
- "@babel/plugin-transform-literals" "^7.10.4"
- "@babel/plugin-transform-member-expression-literals" "^7.10.4"
- "@babel/plugin-transform-modules-amd" "^7.10.4"
- "@babel/plugin-transform-modules-commonjs" "^7.10.4"
- "@babel/plugin-transform-modules-systemjs" "^7.10.4"
- "@babel/plugin-transform-modules-umd" "^7.10.4"
- "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4"
- "@babel/plugin-transform-new-target" "^7.10.4"
- "@babel/plugin-transform-object-super" "^7.10.4"
- "@babel/plugin-transform-parameters" "^7.10.4"
- "@babel/plugin-transform-property-literals" "^7.10.4"
- "@babel/plugin-transform-regenerator" "^7.10.4"
- "@babel/plugin-transform-reserved-words" "^7.10.4"
- "@babel/plugin-transform-shorthand-properties" "^7.10.4"
- "@babel/plugin-transform-spread" "^7.10.4"
- "@babel/plugin-transform-sticky-regex" "^7.10.4"
- "@babel/plugin-transform-template-literals" "^7.10.4"
- "@babel/plugin-transform-typeof-symbol" "^7.10.4"
- "@babel/plugin-transform-unicode-escapes" "^7.10.4"
- "@babel/plugin-transform-unicode-regex" "^7.10.4"
- "@babel/preset-modules" "^0.1.3"
- "@babel/types" "^7.10.4"
- browserslist "^4.12.0"
- core-js-compat "^3.6.2"
- invariant "^2.2.2"
- levenary "^1.1.1"
- semver "^5.5.0"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-top-level-await" "^7.12.13"
+ "@babel/plugin-transform-arrow-functions" "^7.13.0"
+ "@babel/plugin-transform-async-to-generator" "^7.13.0"
+ "@babel/plugin-transform-block-scoped-functions" "^7.12.13"
+ "@babel/plugin-transform-block-scoping" "^7.12.13"
+ "@babel/plugin-transform-classes" "^7.13.0"
+ "@babel/plugin-transform-computed-properties" "^7.13.0"
+ "@babel/plugin-transform-destructuring" "^7.13.0"
+ "@babel/plugin-transform-dotall-regex" "^7.12.13"
+ "@babel/plugin-transform-duplicate-keys" "^7.12.13"
+ "@babel/plugin-transform-exponentiation-operator" "^7.12.13"
+ "@babel/plugin-transform-for-of" "^7.13.0"
+ "@babel/plugin-transform-function-name" "^7.12.13"
+ "@babel/plugin-transform-literals" "^7.12.13"
+ "@babel/plugin-transform-member-expression-literals" "^7.12.13"
+ "@babel/plugin-transform-modules-amd" "^7.13.0"
+ "@babel/plugin-transform-modules-commonjs" "^7.13.8"
+ "@babel/plugin-transform-modules-systemjs" "^7.13.8"
+ "@babel/plugin-transform-modules-umd" "^7.13.0"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13"
+ "@babel/plugin-transform-new-target" "^7.12.13"
+ "@babel/plugin-transform-object-super" "^7.12.13"
+ "@babel/plugin-transform-parameters" "^7.13.0"
+ "@babel/plugin-transform-property-literals" "^7.12.13"
+ "@babel/plugin-transform-regenerator" "^7.12.13"
+ "@babel/plugin-transform-reserved-words" "^7.12.13"
+ "@babel/plugin-transform-shorthand-properties" "^7.12.13"
+ "@babel/plugin-transform-spread" "^7.13.0"
+ "@babel/plugin-transform-sticky-regex" "^7.12.13"
+ "@babel/plugin-transform-template-literals" "^7.13.0"
+ "@babel/plugin-transform-typeof-symbol" "^7.12.13"
+ "@babel/plugin-transform-unicode-escapes" "^7.12.13"
+ "@babel/plugin-transform-unicode-regex" "^7.12.13"
+ "@babel/preset-modules" "^0.1.4"
+ "@babel/types" "^7.13.12"
+ babel-plugin-polyfill-corejs2 "^0.1.4"
+ babel-plugin-polyfill-corejs3 "^0.1.3"
+ babel-plugin-polyfill-regenerator "^0.1.2"
+ core-js-compat "^3.9.0"
+ semver "^6.3.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==
+"@babel/preset-modules@^0.1.4":
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e"
+ integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
@@ -757,43 +800,42 @@
esutils "^2.0.2"
"@babel/runtime@^7.8.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
- integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
+ integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/template@^7.10.4", "@babel/template@^7.4.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
- integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
+"@babel/template@^7.12.13", "@babel/template@^7.4.0":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
+ integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==
dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/parser" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/code-frame" "^7.12.13"
+ "@babel/parser" "^7.12.13"
+ "@babel/types" "^7.12.13"
-"@babel/traverse@^7.10.4", "@babel/traverse@^7.4.3":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818"
- integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.4.3":
+ version "7.13.13"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.13.tgz#39aa9c21aab69f74d948a486dd28a2dbdbf5114d"
+ integrity sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==
dependencies:
- "@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.10.4"
- "@babel/helper-function-name" "^7.10.4"
- "@babel/helper-split-export-declaration" "^7.10.4"
- "@babel/parser" "^7.10.4"
- "@babel/types" "^7.10.4"
+ "@babel/code-frame" "^7.12.13"
+ "@babel/generator" "^7.13.9"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-split-export-declaration" "^7.12.13"
+ "@babel/parser" "^7.13.13"
+ "@babel/types" "^7.13.13"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.13"
-"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee"
- integrity sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==
+"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.13", "@babel/types@^7.13.14", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
+ integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
dependencies:
- "@babel/helper-validator-identifier" "^7.10.4"
- lodash "^4.17.13"
+ "@babel/helper-validator-identifier" "^7.12.11"
+ lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@koa/cors@^3.1.0":
@@ -803,48 +845,48 @@
dependencies:
vary "^1.1.2"
-"@open-wc/building-utils@^2.18.0":
- version "2.18.0"
- resolved "https://registry.yarnpkg.com/@open-wc/building-utils/-/building-utils-2.18.0.tgz#f80929dfcfb6d8a6cb5c933654c721808b4bb2d3"
- integrity sha512-U1n8sLQlLt3IuqhU7tDsGQAGUfVMiB64xJsAmJEtekposrjqkjtRLU/WipvROl1A2GTsrMojMjNbFqzJghpd6g==
+"@open-wc/building-utils@^2.18.0", "@open-wc/building-utils@^2.18.3":
+ version "2.18.4"
+ resolved "https://registry.yarnpkg.com/@open-wc/building-utils/-/building-utils-2.18.4.tgz#397e42039f5d26c38f7a2cc01e347e0e5c2e8e99"
+ integrity sha512-wjNp9oE1SFsiBEqaI67ff60KHDpDbGMNF+82pvCHe412SFY4q8DNy8A+hesj1nZsuZHH1/olDfzBDbYKAnmgMg==
dependencies:
- "@babel/core" "^7.9.0"
+ "@babel/core" "^7.11.1"
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
- "@webcomponents/shadycss" "^1.9.4"
- "@webcomponents/webcomponentsjs" "^2.4.0"
+ "@webcomponents/shadycss" "^1.10.2"
+ "@webcomponents/webcomponentsjs" "^2.5.0"
arrify "^2.0.1"
- browserslist "^4.9.1"
- chokidar "^3.0.0"
- clean-css "^4.2.1"
+ browserslist "^4.16.0"
+ chokidar "^3.4.3"
+ clean-css "^4.2.3"
clone "^2.1.2"
- core-js-bundle "^3.6.0"
+ core-js-bundle "^3.8.1"
deepmerge "^4.2.2"
- es-module-shims "^0.4.6"
- html-minifier "^4.0.0"
+ es-module-shims "^0.4.7"
+ html-minifier-terser "^5.1.1"
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"
+ regenerator-runtime "^0.13.7"
+ resolve "^1.19.0"
rimraf "^3.0.2"
shady-css-scoped-element "^0.0.2"
- systemjs "^6.3.1"
+ systemjs "^6.8.3"
terser "^4.6.7"
valid-url "^1.0.9"
- whatwg-fetch "^3.0.0"
- whatwg-url "^7.0.0"
+ whatwg-fetch "^3.5.0"
+ whatwg-url "^7.1.0"
"@open-wc/karma-esm@^2.16.16":
- version "2.16.16"
- resolved "https://registry.yarnpkg.com/@open-wc/karma-esm/-/karma-esm-2.16.16.tgz#6ebff57f249e95f777b7e04782ef08ed41e22f53"
- integrity sha512-IALT10JfwK+h7T0hGKTUliGdkWzQbyQg195D+RfUteIoTof6Z5+dBp7JUh2fQygIyNj7IIYHJ9ej816QlgHjdA==
+ version "2.16.18"
+ resolved "https://registry.yarnpkg.com/@open-wc/karma-esm/-/karma-esm-2.16.18.tgz#01f3f8c694d7b8dd3aef3159659f3fa9d3090c44"
+ integrity sha512-K+HeXqRdvOupnlRr7rHgBFSqgyr5E0KNS89BTnHN0qKcDpa+M+m1sZHInPrB+iFqLQ7hhWNeGmtesDFfnIBhaQ==
dependencies:
"@open-wc/building-utils" "^2.18.0"
babel-plugin-istanbul "^5.1.4"
chokidar "^3.0.0"
deepmerge "^4.2.2"
- es-dev-server "^1.56.0"
+ es-dev-server "^1.57.0"
minimatch "^3.0.4"
node-fetch "^2.6.0"
polyfills-loader "^1.6.1"
@@ -859,9 +901,9 @@
"@polymer/polymer" "^3.0.0"
"@polymer/polymer@^3.0.0":
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
- integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.4.1.tgz#333bef25711f8411bb5624fb3eba8212ef8bee96"
+ integrity sha512-KPWnhDZibtqKrUz7enIPOiO4ZQoJNOuLwqrhV2MXzIt3VVnUVJVG5ORz4Z2sgO+UZ+/UZnPD0jqY+jmw/+a9mQ==
dependencies:
"@webcomponents/shadycss" "^1.9.1"
@@ -890,10 +932,10 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
-"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
- integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
+"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1":
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b"
+ integrity sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==
dependencies:
type-detect "4.0.8"
@@ -904,18 +946,17 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
-"@sinonjs/formatio@^5.0.1":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089"
- integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==
+"@sinonjs/fake-timers@^7.0.4":
+ version "7.0.5"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.0.5.tgz#558a7f8145a01366c44b3dcbdd7172c05c461564"
+ integrity sha512-fUt6b15bjV/VW93UP5opNXJxdwZSbK1EdiwnhN7XrQrcpaOhMJpZ/CjwFpM3THpxwA+YviBUJKSuEqKlCK5alw==
dependencies:
- "@sinonjs/commons" "^1"
- "@sinonjs/samsam" "^5.0.2"
+ "@sinonjs/commons" "^1.7.0"
-"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3":
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.0.3.tgz#86f21bdb3d52480faf0892a480c9906aa5a52938"
- integrity sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==
+"@sinonjs/samsam@^5.3.1":
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f"
+ integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==
dependencies:
"@sinonjs/commons" "^1.6.0"
lodash.get "^4.4.2"
@@ -934,9 +975,9 @@
"@types/node" "*"
"@types/babel__core@^7.1.3":
- version "7.1.9"
- resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d"
- integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==
+ version "7.1.14"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
+ integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
@@ -945,24 +986,24 @@
"@types/babel__traverse" "*"
"@types/babel__generator@*":
- version "7.6.1"
- resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04"
- integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==
+ version "7.6.2"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8"
+ integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==
dependencies:
"@babel/types" "^7.0.0"
"@types/babel__template@*":
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307"
- integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==
+ version "7.4.0"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be"
+ integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
"@types/babel__traverse@*":
- version "7.0.12"
- resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.12.tgz#22f49a028e69465390f87bb103ebd61bd086b8f5"
- integrity sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA==
+ version "7.11.1"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.1.tgz#654f6c4f67568e24c23b367e947098c6206fa639"
+ integrity sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==
dependencies:
"@babel/types" "^7.3.0"
@@ -975,24 +1016,26 @@
"@types/node" "*"
"@types/browserslist-useragent@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.0.tgz#d425c9818182ce71ce53866798cee9c7d41d6e53"
- integrity sha512-ZBvKzg3yyWNYEkwxAzdmUzp27sFvw+1m080/+2lwrt+eltNefn1f4fnpMyrjOla31p8zLleCYqQXw+3EETfn0w==
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.2.tgz#e4d9a5b3949f7291c0a253e3b9e092e66673114c"
+ integrity sha512-Y2McxEf2m89AgMYgp/E33pxH0DKYHpCHhSSBlPTATnEVatWmHMyWRQpdlOK+BrwcFK62+A+P3mu0s1Owkas9zw==
"@types/browserslist@^4.8.0":
- version "4.8.0"
- resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.8.0.tgz#60489aefdf0fcb56c2d8eb65267ff08dad7a526d"
- integrity sha512-4PyO9OM08APvxxo1NmQyQKlJdowPCOQIy5D/NLO3aO0vGC57wsMptvGp3b8IbYnupFZr92l1dlVief1JvS6STQ==
+ version "4.15.0"
+ resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.15.0.tgz#ba0265b33003a2581df1fc5f483321a30205f2d2"
+ integrity sha512-h9LyKErRGZqMsHh9bd+FE8yCIal4S0DxKTOeui56VgVXqa66TKiuaIUxCAI7c1O0LjaUzOTcsMyOpO9GetozRA==
+ dependencies:
+ browserslist "*"
"@types/caniuse-api@^3.0.0":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/caniuse-api/-/caniuse-api-3.0.0.tgz#af31cc52062be0ab24583be072fd49b634dcc2fe"
- integrity sha512-wT1VfnScjAftZsvLYaefu/UuwYJdYBwD2JDL2OQd01plGmuAoir5V6HnVHgrfh7zEwcasoiyO2wQ+W58sNh2sw==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/caniuse-api/-/caniuse-api-3.0.1.tgz#94c0073a2c305d0476ce9199cd6ef3fd7d2c5f66"
+ integrity sha512-VcjPciJLx86btwWypSo6vRzZSOC6asS3/SGgn7r7Xk7jAWNyMoxCy+IQzI2vuW2Bvs3iytyOEwsjLJKmHXBvmA==
-"@types/chai@^4.2.14":
- version "4.2.14"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193"
- integrity sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==
+"@types/chai@^4.2.16":
+ version "4.2.16"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.16.tgz#f09cc36e18d28274f942e7201147cce34d97e8c8"
+ integrity sha512-vI5iOAsez9+roLS3M3+Xx7w+WRuDtSmF8bQkrbcIJ2sC1PcDgVoA0WGpa+bIrJ+y8zqY2oi//fUctkxtIcXJCw==
"@types/command-line-args@^5.0.0":
version "5.0.0"
@@ -1005,9 +1048,9 @@
integrity sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==
"@types/connect@*":
- version "3.4.33"
- resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
- integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+ version "3.4.34"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
+ integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
dependencies:
"@types/node" "*"
@@ -1017,9 +1060,9 @@
integrity sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==
"@types/cookies@*":
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.4.tgz#26dedf791701abc0e36b5b79a5722f40e455f87b"
- integrity sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==
+ version "0.7.6"
+ resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.6.tgz#71212c5391a976d3bae57d4b09fac20fc6bda504"
+ integrity sha512-FK4U5Qyn7/Sc5ih233OuHO0qAkOpEcD/eG6584yEiLKizTFRny86qHLe/rej3HFQrkBuUjF4whFliAdODbVN/w==
dependencies:
"@types/connect" "*"
"@types/express" "*"
@@ -1043,22 +1086,22 @@
dependencies:
"@types/node" "*"
-"@types/express-serve-static-core@*":
- version "4.17.8"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz#b8f7b714138536742da222839892e203df569d1c"
- integrity sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==
+"@types/express-serve-static-core@^4.17.18":
+ version "4.17.19"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
+ integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==
dependencies:
"@types/node" "*"
"@types/qs" "*"
"@types/range-parser" "*"
"@types/express@*":
- version "4.17.6"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e"
- integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545"
+ integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==
dependencies:
"@types/body-parser" "*"
- "@types/express-serve-static-core" "*"
+ "@types/express-serve-static-core" "^4.17.18"
"@types/qs" "*"
"@types/serve-static" "*"
@@ -1067,6 +1110,11 @@
resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b"
integrity sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==
+"@types/http-errors@*":
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69"
+ integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==
+
"@types/keygrip@*":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72"
@@ -1111,54 +1159,60 @@
"@types/koa-send" "*"
"@types/koa@*", "@types/koa@^2.0.48":
- version "2.11.3"
- resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.3.tgz#540ece376581b12beadf9a417dd1731bc31c16ce"
- integrity sha512-ABxVkrNWa4O/Jp24EYI/hRNqEVRlhB9g09p48neQp4m3xL1TJtdWk2NyNQSMCU45ejeELMQZBYyfstyVvO2H3Q==
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.1.tgz#e29877a6b5ad3744ab1024f6ec75b8cbf6ec45db"
+ integrity sha512-Qbno7FWom9nNqu0yHZ6A0+RWt4mrYBhw3wpBAQ3+IuzGcLlfeYkzZrnMq5wsxulN2np8M4KKeUpTodsOsSad5Q==
dependencies:
"@types/accepts" "*"
"@types/content-disposition" "*"
"@types/cookies" "*"
"@types/http-assert" "*"
+ "@types/http-errors" "*"
"@types/keygrip" "*"
"@types/koa-compose" "*"
"@types/node" "*"
"@types/koa__cors@^3.0.1":
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.0.1.tgz#a8cf8535f0fe682c9421f1b9379837c585f8b66b"
- integrity sha512-loqZNXliley8kncc4wrX9KMqLGN6YfiaO3a3VFX+yVkkXJwOrZU4lipdudNjw5mFyC+5hd7h9075hQWcVVpeOg==
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.0.2.tgz#578917ffca964e98f5e9849996ae1eeda7c15704"
+ integrity sha512-gBetQR0DJ9JTG1YQoW33BADHCrDPJGiJUKUUcEPJwW1A2unzpIMhorEpXB6eMaaXTaqHLemcGnq3RmH9XaryRQ==
dependencies:
"@types/koa" "*"
-"@types/lodash@^4.14.162":
- version "4.14.162"
- resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.162.tgz#65d78c397e0d883f44afbf1f7ba9867022411470"
- integrity sha512-alvcho1kRUnnD1Gcl4J+hK0eencvzq9rmzvFPRmP5rPHx9VVsJj6bKLTATPVf9ktgv4ujzh7T+XWKp+jhuODig==
+"@types/lodash@^4.14.168":
+ version "4.14.168"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
+ integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
"@types/lru-cache@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03"
integrity sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==
-"@types/mime@*":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
- integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==
+"@types/mime-types@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73"
+ integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=
+
+"@types/mime@^1":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
+ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
"@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==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
+ integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
-"@types/mocha@^8.0.3":
- version "8.0.3"
- resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.3.tgz#51b21b6acb6d1b923bbdc7725c38f9f455166402"
- integrity sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==
+"@types/mocha@^8.2.2":
+ version "8.2.2"
+ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0"
+ integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==
"@types/node@*":
- version "14.0.14"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce"
- integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==
+ version "14.14.37"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
+ integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
"@types/path-is-inside@^1.0.0":
version "1.0.0"
@@ -1166,9 +1220,9 @@
integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
"@types/qs@*":
- version "6.9.3"
- resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03"
- integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==
+ version "6.9.6"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
+ integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
"@types/range-parser@*":
version "1.2.3"
@@ -1183,24 +1237,19 @@
"@types/node" "*"
"@types/serve-static@*":
- version "1.13.4"
- resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c"
- integrity sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==
+ version "1.13.9"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
+ integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
dependencies:
- "@types/express-serve-static-core" "*"
- "@types/mime" "*"
+ "@types/mime" "^1"
+ "@types/node" "*"
-"@types/sinon@^9.0.8":
- version "9.0.8"
- resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.8.tgz#1ed0038d356784f75b086104ef83bfd4130bb81b"
- integrity sha512-IVnI820FZFMGI+u1R+2VdRaD/82YIQTdqLYC9DLPszZuynAJDtCvCtCs3bmyL66s7FqRM3+LPX7DhHnVTaagDw==
+"@types/sinon@^10.0.0":
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.0.tgz#eecc3847af03d45ffe53d55aaaaf6ecb28b5e584"
+ integrity sha512-jDZ55oCKxqlDmoTBBbBBEx+N8ZraUVhggMZ9T5t+6/Dh8/4NiOjSUfpLrPiEwxQDlAe3wpAkoXhWvE6LibtsMQ==
dependencies:
- "@types/sinonjs__fake-timers" "*"
-
-"@types/sinonjs__fake-timers@*":
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae"
- integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==
+ "@sinonjs/fake-timers" "^7.0.4"
"@types/whatwg-url@^6.4.0":
version "6.4.0"
@@ -1209,25 +1258,25 @@
dependencies:
"@types/node" "*"
-"@webcomponents/shadycss@^1.9.1":
- version "1.9.4"
- resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
- integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+"@ungap/promise-all-settled@1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
+ integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
-"@webcomponents/shadycss@^1.9.4":
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.0.tgz#7a80ec1e8b271fb3f0cc02cd4358b877a303545d"
- integrity sha512-UMS+dF4DXDrcUmQqK6aLd/3mFyfGktKG/hZR6FtrsQK/INO07G0H8FxElLkuvHj0iePeZGpR7R4lWFTvX7rc9g==
+"@webcomponents/shadycss@^1.10.2", "@webcomponents/shadycss@^1.9.1":
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.2.tgz#40e03cab6dc5e12f199949ba2b79e02f183d1e7b"
+ integrity sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==
-"@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==
+"@webcomponents/webcomponentsjs@^2.4.0", "@webcomponents/webcomponentsjs@^2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.5.0.tgz#61b27785a6ad5bfd68fa018201fe418b118cb38d"
+ integrity sha512-C0l51MWQZ9kLzcxOZtniOMohpIFdCLZum7/TEHv3XWFc1Fvt5HCpbSX84x8ltka/JuNKcuiDnxXFkiB2gaePcg==
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==
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.1.tgz#27084bac87d78a7224c8ee78135d05df430c2d2f"
+ integrity sha512-yml9NiDEH4M4p0G4AcPkg8AAa4mF3nfYF28VQxaokpO67j9H7gWgmsVWJ/f1Rn+PzsnDYvzJzWIQzCqDKRvWlA==
accepts@^1.3.5, accepts@~1.3.4:
version "1.3.7"
@@ -1247,20 +1296,20 @@
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
-ajv@^6.5.5:
- version "6.12.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
- integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
+ajv@^6.12.3:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ansi-colors@3.2.3:
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
- integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+ansi-colors@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+ integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-regex@^3.0.0:
version "3.0.0"
@@ -1272,39 +1321,49 @@
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+ansi-regex@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+ integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+
+ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
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==
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+ integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
- dependencies:
- sprintf-js "~1.0.2"
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
array-back@^3.0.1:
version "3.1.0"
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:
+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==
@@ -1359,9 +1418,9 @@
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
- integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
babel-plugin-dynamic-import-node@^2.3.3:
version "2.3.3"
@@ -1380,15 +1439,39 @@
istanbul-lib-instrument "^3.3.0"
test-exclude "^5.2.3"
+babel-plugin-polyfill-corejs2@^0.1.4:
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1"
+ integrity sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==
+ dependencies:
+ "@babel/compat-data" "^7.13.0"
+ "@babel/helper-define-polyfill-provider" "^0.1.5"
+ semver "^6.1.1"
+
+babel-plugin-polyfill-corejs3@^0.1.3:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz#80449d9d6f2274912e05d9e182b54816904befd0"
+ integrity sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.1.5"
+ core-js-compat "^3.8.1"
+
+babel-plugin-polyfill-regenerator@^0.1.2:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz#0fe06a026fe0faa628ccc8ba3302da0a6ce02f3f"
+ integrity sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.1.5"
+
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@0.1.5:
version "0.1.5"
@@ -1415,9 +1498,9 @@
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==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
blob@0.0.5:
version "0.0.5"
@@ -1474,15 +1557,16 @@
semver "^7.3.2"
useragent "^2.3.0"
-browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5, browserslist@^4.9.1:
- version "4.12.2"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.2.tgz#76653d7e4c57caa8a1a28513e2f4e197dc11a711"
- integrity sha512-MfZaeYqR8StRZdstAK9hCKDd2StvePCYp5rHzQCPicUjfFliDgmuaBNPHYUTpAywBN8+Wc/d7NYVFkO0aqaBUw==
+browserslist@*, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.3, browserslist@^4.9.1:
+ version "4.16.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
+ integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
dependencies:
- caniuse-lite "^1.0.30001088"
- electron-to-chromium "^1.3.483"
- escalade "^3.0.1"
- node-releases "^1.1.58"
+ caniuse-lite "^1.0.30001181"
+ colorette "^1.2.1"
+ electron-to-chromium "^1.3.649"
+ escalade "^3.1.1"
+ node-releases "^1.1.70"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
@@ -1508,9 +1592,9 @@
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
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==
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
+ integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
bytes@3.1.0, bytes@^3.0.0:
version "3.1.0"
@@ -1525,24 +1609,37 @@
mime-types "^2.1.18"
ylru "^1.2.0"
+call-bind@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.2"
+
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.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
- integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+camel-case@^4.1.1:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+ integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
dependencies:
- no-case "^2.2.0"
- upper-case "^1.1.1"
+ pascal-case "^3.1.2"
+ tslib "^2.0.3"
-camelcase@^5.0.0, camelcase@^5.3.1:
+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==
+camelcase@^6.0.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
+ integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
+
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -1553,26 +1650,26 @@
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001033, caniuse-lite@^1.0.30001088:
- version "1.0.30001093"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001093.tgz#833e80f64b1a0455cbceed2a4a3baf19e4abd312"
- integrity sha512-0+ODNoOjtWD5eS9aaIpf4K0gQqZfILNY4WSNuYzeT1sXni+lMrrVjc0odEobJt6wrODofDZUX8XYi/5y7+xl8g==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001033, caniuse-lite@^1.0.30001181:
+ version "1.0.30001207"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001207.tgz#364d47d35a3007e528f69adb6fecb07c2bb2cc50"
+ integrity sha512-UPQZdmAsyp2qfCTiMU/zqGSWOYaY9F9LL61V8f+8MrubsaDGpaHD9HRV/EWZGULZn0Hxu48SKzI5DgFwTvHuYw==
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-chai@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
- integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
+chai@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
+ integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
dependencies:
assertion-error "^1.1.0"
check-error "^1.0.2"
deep-eql "^3.0.1"
get-func-name "^2.0.0"
- pathval "^1.1.0"
+ pathval "^1.1.1"
type-detect "^4.0.5"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
@@ -1584,15 +1681,23 @@
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
+chalk@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
+ integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
check-error@^1.0.2:
version "1.0.2"
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==
+chokidar@3.5.1, chokidar@^3.0.0, chokidar@^3.4.3:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
+ integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
@@ -1600,40 +1705,25 @@
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
- readdirp "~3.2.0"
+ readdirp "~3.5.0"
optionalDependencies:
- fsevents "~2.1.1"
+ fsevents "~2.3.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"
-
-clean-css@^4.2.1:
+clean-css@^4.2.3:
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"
-cliui@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
- integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
dependencies:
- string-width "^3.1.0"
- strip-ansi "^5.2.0"
- wrap-ansi "^5.1.0"
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
clone@^2.1.2:
version "2.1.2"
@@ -1652,11 +1742,28 @@
dependencies:
color-name "1.1.3"
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+colorette@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+ integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+
colors@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@@ -1680,20 +1787,25 @@
typical "^4.0.0"
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==
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.1.tgz#c908e28686108917758a49f45efb4f02f76bc03f"
+ integrity sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==
dependencies:
- array-back "^4.0.0"
+ array-back "^4.0.1"
chalk "^2.4.2"
- table-layout "^1.0.0"
+ table-layout "^1.0.1"
typical "^5.2.0"
-commander@^2.19.0, commander@^2.20.0:
+commander@^2.20.0:
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==
+commander@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+ integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
@@ -1763,17 +1875,17 @@
depd "~2.0.0"
keygrip "~1.1.0"
-core-js-bundle@^3.6.0:
- version "3.6.5"
- resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.6.5.tgz#3a425ad66ad19aeefea89acfd48cff674ff58590"
- integrity sha512-awf49McIBT3sDXceSex69w/i7PMXQwxI4ZqknCtaYbW4Q0u0HUZiaQLlPD6pU2nFBofIowgWIS1ANgHjqnQu4Q==
+core-js-bundle@^3.6.0, core-js-bundle@^3.8.1:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.10.0.tgz#8559ce25d36f8094bcafdf7d1a24d50c706dcbe5"
+ integrity sha512-Rh+60FxNOd23Fm35vK/P3U1usjte2VNKBBW9bGZym5cV2Cc9pgviMQjSEOe8llIZAZjbr5NuL4GoeBK8DM3ewg==
-core-js-compat@^3.6.2:
- version "3.6.5"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c"
- integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==
+core-js-compat@^3.8.1, core-js-compat@^3.9.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.10.0.tgz#3600dc72869673c110215ee7a005a8609dea0fe1"
+ integrity sha512-9yVewub2MXNYyGvuLnMHcN1k9RkvB7/ofktpeKTIaASyB88YYqGzUnu0ywMMhJrDHOMiTjSHWGzR+i7Wb9Z1kQ==
dependencies:
- browserslist "^4.8.5"
+ browserslist "^4.16.3"
semver "7.0.0"
core-util-is@1.0.2:
@@ -1799,9 +1911,9 @@
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==
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+ integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
debug@2.6.9:
version "2.6.9"
@@ -1810,17 +1922,17 @@
dependencies:
ms "2.0.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==
+debug@4.3.1, debug@^4.1.0, debug@^4.1.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
+ integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
- ms "^2.1.1"
+ ms "2.1.2"
-debug@^4.1.0, debug@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
@@ -1831,10 +1943,10 @@
dependencies:
ms "2.0.0"
-decamelize@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+decamelize@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+ integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
deep-eql@^3.0.1:
version "3.0.1"
@@ -1858,7 +1970,7 @@
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
-define-properties@^1.1.2, define-properties@^1.1.3:
+define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -1875,16 +1987,16 @@
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=
-
-depd@~2.0.0:
+depd@^2.0.0, 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==
+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:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
@@ -1895,10 +2007,10 @@
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=
-diff@3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
- integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+ integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
diff@^4.0.2:
version "4.0.2"
@@ -1915,6 +2027,14 @@
extend "^3.0.0"
void-elements "^2.0.0"
+dot-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+ integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
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"
@@ -1933,15 +2053,15 @@
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-electron-to-chromium@^1.3.483:
- version "1.3.486"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.486.tgz#90856e6c9f488079225cf5a0b4d4af6c241e0965"
- integrity sha512-fmnACh6Jiuagm9tAfEZNe6QrwvOYAC5y0BwzoEOGCsbqriKOCaafXf3lsIvL55xa75Jmg4oboI7f5tMuoXrjNg==
+electron-to-chromium@^1.3.649:
+ version "1.3.709"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.709.tgz#d7be0b5686a2fdfe8bad898faa3a428d04d8f656"
+ integrity sha512-LolItk2/ikSGQ7SN8UkuKVNMBZp3RG7Itgaxj1npsHRzQobj9JjMneZOZfLhtwlYBe5fCJ75k+cVCiDFUs23oA==
-emoji-regex@^7.0.1:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
- integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
encodeurl@^1.0.2, encodeurl@~1.0.2:
version "1.0.2"
@@ -2007,41 +2127,24 @@
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
- version "1.17.6"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
- integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
+es-dev-server@^1.57.0:
+ version "1.60.2"
+ resolved "https://registry.yarnpkg.com/es-dev-server/-/es-dev-server-1.60.2.tgz#cca56fe452d46c3ec531c19745e0aa9d7b71e1b3"
+ integrity sha512-Lp9kZzawJ35HDKiqLNb/YbD2VufF+3tdxHgbP/kfdLI5JLgDJV4SuKTWWny3ZuBUAlZKGre7a0iXUByGQqfdPA==
dependencies:
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
- is-callable "^1.2.0"
- is-regex "^1.1.0"
- object-inspect "^1.7.0"
- object-keys "^1.1.1"
- object.assign "^4.1.0"
- string.prototype.trimend "^1.0.1"
- string.prototype.trimstart "^1.0.1"
-
-es-dev-server@^1.56.0:
- version "1.56.0"
- resolved "https://registry.yarnpkg.com/es-dev-server/-/es-dev-server-1.56.0.tgz#8703af87595f02fe9a1c92a07e64b7c7cc915a87"
- integrity sha512-SL4CXdiku0hiB8zpsBLtEd7b8etIZE6IV0tIi02m0CcpTYV0rDMEvCBUYsQIN5hggJDDTBURgQjOWcT5kQv2eA==
- 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/core" "^7.11.1"
+ "@babel/plugin-proposal-dynamic-import" "^7.10.4"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4"
+ "@babel/plugin-proposal-optional-chaining" "^7.11.0"
"@babel/plugin-syntax-class-properties" "^7.8.3"
- "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.10.4"
"@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"
"@koa/cors" "^3.1.0"
- "@open-wc/building-utils" "^2.18.0"
+ "@open-wc/building-utils" "^2.18.3"
"@rollup/plugin-node-resolve" "^7.1.1"
"@rollup/pluginutils" "^3.0.0"
"@types/babel__core" "^7.1.3"
@@ -2057,6 +2160,7 @@
"@types/koa-static" "^4.0.1"
"@types/koa__cors" "^3.0.1"
"@types/lru-cache" "^5.1.0"
+ "@types/mime-types" "^2.1.0"
"@types/minimatch" "^3.0.3"
"@types/path-is-inside" "^1.0.0"
"@types/whatwg-url" "^6.4.0"
@@ -2085,7 +2189,7 @@
open "^7.0.3"
parse5 "^5.1.1"
path-is-inside "^1.0.2"
- polyfills-loader "^1.6.1"
+ polyfills-loader "^1.7.4"
portfinder "^1.0.21"
rollup "^2.7.2"
strip-ansi "^5.2.0"
@@ -2095,44 +2199,35 @@
whatwg-url "^7.0.0"
es-module-lexer@^0.3.13:
- version "0.3.24"
- resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.24.tgz#e6b2900758e9e210d23aec2092efc13ca235adea"
- integrity sha512-jm/i7KdJtaMDle921xIsA/MQQOGuZ6goYxhlV+k+gQNI7FtP4N6jknrmJvj++3ODpiyFGwQ4PIstJfHJQJNc+g==
+ version "0.3.26"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
+ integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
-es-module-shims@^0.4.6:
+es-module-shims@^0.4.6, es-module-shims@^0.4.7:
version "0.4.7"
resolved "https://registry.yarnpkg.com/es-module-shims/-/es-module-shims-0.4.7.tgz#1419b65bbd38dfe91ab8ea5d7b4b454561e44641"
integrity sha512-0LTiSQoPWwdcaTVIQXhGlaDwTneD0g9/tnH1PNs3zHFFH+xoCeJclDM3rQeqF9nurXPfMKm3l9+kfPRa5VpbKg==
-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"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
-
-escalade@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.1.tgz#52568a77443f6927cd0ab9c73129137533c965ed"
- integrity sha512-DR6NO3h9niOT+MZs7bjxlj2a1k+POu5RN8CLTPX2+i78bRi9eLe7+0zXgUHMnGXWybYcL61E9hGhPKqedy8tQA==
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
-escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
+escape-string-regexp@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-esprima@^4.0.0:
- version "4.0.1"
- 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"
@@ -2149,9 +2244,9 @@
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
- integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
extend@^3.0.0, extend@~3.0.2:
version "3.0.2"
@@ -2205,19 +2300,25 @@
dependencies:
array-back "^3.0.1"
-find-up@3.0.0, find-up@^3.0.0:
+find-up@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
dependencies:
locate-path "^3.0.0"
-flat@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
- integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
- dependencies:
- is-buffer "~2.0.3"
+flat@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+ integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
flatted@^2.0.0:
version "2.0.2"
@@ -2225,11 +2326,9 @@
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"
- integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
- dependencies:
- debug "^3.0.0"
+ version "1.13.3"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
+ integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
forever-agent@~0.6.1:
version "0.6.1"
@@ -2264,27 +2363,22 @@
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@~2.1.1:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
- integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
-
-fsevents@~2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
- integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+fsevents@~2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-gensync@^1.0.0-beta.1:
- version "1.0.0-beta.1"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
- integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-get-caller-file@^2.0.1:
+get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@@ -2294,10 +2388,19 @@
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
+get-intrinsic@^1.0.2:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+
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==
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
@@ -2309,25 +2412,13 @@
assert-plus "^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==
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
-glob@7.1.3:
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
- integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.1.1, glob@^7.1.3:
+glob@7.1.6, glob@^7.1.1, glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -2345,9 +2436,9 @@
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
- integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+ version "4.2.6"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
+ integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
growl@1.10.5:
version "1.10.5"
@@ -2360,11 +2451,11 @@
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
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==
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
- ajv "^6.5.5"
+ ajv "^6.12.3"
har-schema "^2.0.0"
has-binary2@~1.0.2:
@@ -2389,10 +2480,10 @@
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-symbols@^1.0.0, has-symbols@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+has-symbols@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
+ integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has@^1.0.3:
version "1.0.3"
@@ -2411,18 +2502,18 @@
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
-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==
+html-minifier-terser@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054"
+ integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==
dependencies:
- camel-case "^3.0.0"
- clean-css "^4.2.1"
- commander "^2.19.0"
+ camel-case "^4.1.1"
+ clean-css "^4.2.3"
+ commander "^4.1.1"
he "^1.2.0"
- param-case "^2.1.1"
+ param-case "^3.0.3"
relateurl "^0.2.7"
- uglify-js "^3.5.1"
+ terser "^4.6.3"
http-assert@^1.3.0:
version "1.4.1"
@@ -2443,7 +2534,7 @@
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
-http-errors@^1.6.3:
+http-errors@^1.6.3, http-errors@^1.7.3:
version "1.8.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
@@ -2476,9 +2567,9 @@
toidentifier "1.0.0"
http-proxy@^1.13.0:
- 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==
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
@@ -2528,13 +2619,6 @@
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==
- dependencies:
- loose-envify "^1.0.0"
-
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -2547,25 +2631,17 @@
dependencies:
binary-extensions "^2.0.0"
-is-buffer@~2.0.3:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
- integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
-
-is-callable@^1.1.4, is-callable@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
- integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
-
-is-date-object@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
- integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+is-core-module@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
+ integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
+ dependencies:
+ has "^1.0.3"
is-docker@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b"
- integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.0.tgz#b037c8815281edaad6c2562648a5f5f18839d5f7"
+ integrity sha512-K4GwB4i/HzhAzwP/XSlspzRdFTI9N8OxJOyOU7Y5Rz+p+WBokXWVWblaJeBkggthmoSV0OoGTH5thJNvplpkvQ==
is-extglob@^2.1.1:
version "2.1.1"
@@ -2577,10 +2653,15 @@
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
is-generator-function@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
- integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b"
+ integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
@@ -2599,25 +2680,16 @@
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-is-regex@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
- integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
- dependencies:
- has-symbols "^1.0.1"
+is-plain-obj@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+ integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
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"
- integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
- dependencies:
- has-symbols "^1.0.1"
-
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@@ -2680,18 +2752,17 @@
istanbul-lib-coverage "^2.0.5"
semver "^6.0.0"
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^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"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@3.13.1:
- version "3.13.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
- integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+js-yaml@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
+ integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
+ argparse "^2.0.1"
jsbn@~0.1.0:
version "0.1.1"
@@ -2729,9 +2800,9 @@
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json5@^2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
- integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
+ integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
@@ -2753,9 +2824,9 @@
verror "1.10.0"
just-extend@^4.0.2:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4"
- integrity sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744"
+ integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==
karma-chrome-launcher@^3.1.0:
version "3.1.0"
@@ -2863,13 +2934,12 @@
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==
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
+ integrity sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==
dependencies:
- debug "^3.1.0"
- http-errors "^1.6.3"
- mz "^2.7.0"
+ debug "^4.1.1"
+ http-errors "^1.7.3"
resolve-path "^1.4.0"
koa-static@^5.0.0:
@@ -2881,9 +2951,9 @@
koa-send "^5.0.0"
koa@^2.7.0:
- version "2.13.0"
- resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.0.tgz#25217e05efd3358a7e5ddec00f0a380c9b71b501"
- integrity sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.1.tgz#6275172875b27bcfe1d454356a5b6b9f5a9b1051"
+ integrity sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w==
dependencies:
accepts "^1.3.5"
cache-content-type "^1.0.0"
@@ -2892,7 +2962,7 @@
cookies "~0.8.0"
debug "~3.1.0"
delegates "^1.0.0"
- depd "^1.1.2"
+ depd "^2.0.0"
destroy "^1.0.4"
encodeurl "^1.0.2"
escape-html "^1.0.3"
@@ -2909,18 +2979,6 @@
type-is "^1.6.16"
vary "^1.1.2"
-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@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -2939,11 +2997,23 @@
p-locate "^3.0.0"
path-exists "^3.0.0"
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+ integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
+
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
@@ -2964,17 +3034,17 @@
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
- version "4.17.15"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
- integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-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==
+log-symbols@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
+ integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==
dependencies:
- chalk "^2.4.2"
+ chalk "^4.0.0"
log-symbols@^2.1.0:
version "2.2.0"
@@ -2994,17 +3064,12 @@
rfdc "^1.1.4"
streamroller "^1.0.6"
-loose-envify@^1.0.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+lower-case@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+ integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
-lower-case@^1.1.1:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
- integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+ tslib "^2.0.3"
lru-cache@4.1.x:
version "4.1.5"
@@ -3021,39 +3086,34 @@
dependencies:
yallist "^3.0.2"
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
-mime-db@1.43.0:
- version "1.43.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
- integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+mime-db@1.47.0, "mime-db@>= 1.43.0 < 2":
+ version "1.47.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
+ integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
-mime-db@1.44.0, "mime-db@>= 1.43.0 < 2":
- version "1.44.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
- integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
-
-mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.19:
- version "2.1.27"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
- integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
+mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24:
+ version "2.1.30"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
+ integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
dependencies:
- mime-db "1.44.0"
-
-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==
- dependencies:
- mime-db "1.43.0"
+ mime-db "1.47.0"
mime@^2.3.1:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
- integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
+ integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
@@ -3072,59 +3132,60 @@
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
-mkdirp@0.5.5, mkdirp@^0.5.1:
+mkdirp@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"
-mocha@7.2.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604"
- integrity sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==
+mocha@8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.2.tgz#53406f195fa86fbdebe71f8b1c6fb23221d69fcc"
+ integrity sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==
dependencies:
- ansi-colors "3.2.3"
+ "@ungap/promise-all-settled" "1.1.2"
+ ansi-colors "4.1.1"
browser-stdout "1.3.1"
- chokidar "3.3.0"
- debug "3.2.6"
- diff "3.5.0"
- escape-string-regexp "1.0.5"
- find-up "3.0.0"
- glob "7.1.3"
+ chokidar "3.5.1"
+ debug "4.3.1"
+ diff "5.0.0"
+ escape-string-regexp "4.0.0"
+ find-up "5.0.0"
+ glob "7.1.6"
growl "1.10.5"
he "1.2.0"
- js-yaml "3.13.1"
- log-symbols "3.0.0"
+ js-yaml "4.0.0"
+ log-symbols "4.0.0"
minimatch "3.0.4"
- mkdirp "0.5.5"
- ms "2.1.1"
- 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"
+ ms "2.1.3"
+ nanoid "3.1.20"
+ serialize-javascript "5.0.1"
+ strip-json-comments "3.1.1"
+ supports-color "8.1.1"
+ which "2.0.2"
wide-align "1.1.3"
- yargs "13.3.2"
- yargs-parser "13.1.2"
- yargs-unparser "1.6.0"
+ workerpool "6.1.0"
+ yargs "16.2.0"
+ yargs-parser "20.2.4"
+ yargs-unparser "2.0.0"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-ms@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-ms@^2.1.1:
+ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-mz@^2.1.0, mz@^2.7.0:
+ms@2.1.3, ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+mz@^2.1.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
@@ -3133,15 +3194,20 @@
object-assign "^4.0.1"
thenify-all "^1.0.0"
+nanoid@3.1.20:
+ version "3.1.20"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
+ integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
+
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
-nise@^4.0.1:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd"
- integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==
+nise@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6"
+ integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@sinonjs/fake-timers" "^6.0.0"
@@ -3149,30 +3215,23 @@
just-extend "^4.0.2"
path-to-regexp "^1.7.0"
-no-case@^2.2.0:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
- integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+no-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+ integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
dependencies:
- lower-case "^1.1.1"
-
-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"
+ lower-case "^2.0.2"
+ tslib "^2.0.3"
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==
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+ integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
-node-releases@^1.1.58:
- version "1.1.58"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935"
- integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==
+node-releases@^1.1.70:
+ version "1.1.71"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
+ integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
normalize-package-data@^2.3.2:
version "2.5.0"
@@ -3204,33 +3263,20 @@
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
-object-inspect@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
- integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
-
-object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-object.assign@4.1.0, object.assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+object.assign@^4.1.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+ integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
-
-object.getownpropertydescriptors@^2.0.3:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
- integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==
- dependencies:
+ call-bind "^1.0.0"
define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
+ has-symbols "^1.0.1"
+ object-keys "^1.1.1"
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
@@ -3252,9 +3298,9 @@
integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=
open@^7.0.3:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/open/-/open-7.0.4.tgz#c28a9d315e5c98340bf979fdcb2e58664aa10d83"
- integrity sha512-brSA+/yq+b08Hsr4c8fsEW2CRzk1BmfN3SAK/5VCHQ9bdoZJ4qa/+AfR0xHjlbbZUyPkUHs1b8x1RqdyZdkVqQ==
+ version "7.4.2"
+ resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
+ integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
dependencies:
is-docker "^2.0.0"
is-wsl "^2.1.1"
@@ -3273,12 +3319,19 @@
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
p-limit@^2.0.0:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
- integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.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"
@@ -3286,17 +3339,25 @@
dependencies:
p-limit "^2.0.0"
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-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=
+param-case@^3.0.3:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+ integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
dependencies:
- no-case "^2.2.0"
+ dot-case "^3.0.4"
+ tslib "^2.0.3"
parse-json@^4.0.0:
version "4.0.0"
@@ -3330,11 +3391,24 @@
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+pascal-case@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+ integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
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"
@@ -3364,17 +3438,17 @@
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"
- integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+pathval@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+ integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
performance-now@^2.1.0:
version "2.1.0"
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, picomatch@^2.2.2:
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
@@ -3384,20 +3458,19 @@
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
-polyfills-loader@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/polyfills-loader/-/polyfills-loader-1.6.1.tgz#134ab74b9a6160efb4d72066a5150bfb2228fad3"
- integrity sha512-GK3jZGLy9nApfRYfHrrO4RYkBkpjiXUVWVdp169g4Y8HV+ZazrGQX46tNpbwP0dtrgHgADyJvZYPfdFuooHy5Q==
+polyfills-loader@^1.6.1, polyfills-loader@^1.7.4:
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/polyfills-loader/-/polyfills-loader-1.7.6.tgz#5cff98bfc9689cf10e44bdd32f498cfeb4374c51"
+ integrity sha512-AiLIgmGFmzcvsqewyKsqWb7H8CnWNTSQBoM0u+Mauzmp0DsjObXmnZdeqvTn0HNwc1wYHHTOta82WjSjG341eQ==
dependencies:
- "@babel/core" "^7.9.0"
- "@open-wc/building-utils" "^2.18.0"
+ "@babel/core" "^7.11.1"
+ "@open-wc/building-utils" "^2.18.3"
"@webcomponents/webcomponentsjs" "^2.4.0"
abortcontroller-polyfill "^1.4.0"
core-js-bundle "^3.6.0"
deepmerge "^4.2.2"
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"
@@ -3407,13 +3480,13 @@
whatwg-fetch "^3.0.0"
portfinder@^1.0.21:
- version "1.0.26"
- resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
- integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==
+ version "1.0.28"
+ resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
+ integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==
dependencies:
async "^2.6.2"
debug "^3.1.1"
- mkdirp "^0.5.1"
+ mkdirp "^0.5.5"
pseudomap@^1.0.2:
version "1.0.2"
@@ -3453,6 +3526,13 @@
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
range-parser@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -3485,19 +3565,12 @@
normalize-package-data "^2.3.2"
path-type "^3.0.0"
-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==
+readdirp@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
+ integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
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"
+ picomatch "^2.2.1"
reduce-flatten@^2.0.0:
version "2.0.0"
@@ -3512,14 +3585,14 @@
regenerate "^1.4.0"
regenerate@^1.4.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
- integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
+ integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-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-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
+ version "0.13.7"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+ integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regenerator-transform@^0.14.2:
version "0.14.5"
@@ -3528,10 +3601,10 @@
dependencies:
"@babel/runtime" "^7.8.4"
-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==
+regexpu-core@^4.7.1:
+ version "4.7.1"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
+ integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
dependencies:
regenerate "^1.4.0"
regenerate-unicode-properties "^8.2.0"
@@ -3546,9 +3619,9 @@
integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
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==
+ version "0.6.9"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
+ integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
dependencies:
jsesc "~0.5.0"
@@ -3611,17 +3684,18 @@
http-errors "~1.6.2"
path-is-absolute "1.0.1"
-resolve@^1.10.0, resolve@^1.11.1, resolve@^1.14.2, resolve@^1.3.2:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
- integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0:
+ version "1.20.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
+ is-core-module "^2.2.0"
path-parse "^1.0.6"
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==
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
+ integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
rimraf@^2.6.0:
version "2.7.1"
@@ -3638,23 +3712,18 @@
glob "^7.1.3"
rollup@^2.7.2:
- version "2.18.2"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.18.2.tgz#886ac6e4549e493df106c3e2580c89aeb997be25"
- integrity sha512-+mzyZhL9ZyLB3eHBISxRNTep9Z2qCuwXzAYkUbFyz7yNKaKH03MFKeiGOS1nv2uvPgDb4ASKv+FiS5mC4h5IFQ==
+ version "2.44.0"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.44.0.tgz#8da324d1c4fd12beef9ae6e12f4068265b6d95eb"
+ integrity sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==
optionalDependencies:
- fsevents "~2.1.2"
+ fsevents "~2.3.1"
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-buffer@^5.0.1:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
- integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
-
-safe-buffer@^5.1.2:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -3664,7 +3733,7 @@
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.7.0:
+"semver@2 || 3 || 4 || 5":
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -3674,20 +3743,24 @@
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
-semver@^6.0.0:
+semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, 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==
semver@^7.3.2:
- version "7.3.2"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
- integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+ version "7.3.5"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+ dependencies:
+ lru-cache "^6.0.0"
-set-blocking@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+serialize-javascript@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
+ integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
+ dependencies:
+ randombytes "^2.1.0"
setprototypeof@1.1.0:
version "1.1.0"
@@ -3709,17 +3782,16 @@
resolved "https://registry.yarnpkg.com/shady-css-scoped-element/-/shady-css-scoped-element-0.0.2.tgz#c538fcfe2317e979cd02dfec533898b95b4ea8fe"
integrity sha512-Dqfl70x6JiwYDujd33ZTbtCK0t52E7+H2swdWQNSTzfsolSa6LJHnTpN4T9OpJJEq4bxuzHRLFO9RBcy/UfrMQ==
-sinon@^9.0.2:
- version "9.0.2"
- resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d"
- integrity sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==
+sinon@^10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/sinon/-/sinon-10.0.0.tgz#52279f97e35646ff73d23207d0307977c9b81430"
+ integrity sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==
dependencies:
- "@sinonjs/commons" "^1.7.2"
+ "@sinonjs/commons" "^1.8.1"
"@sinonjs/fake-timers" "^6.0.1"
- "@sinonjs/formatio" "^5.0.1"
- "@sinonjs/samsam" "^5.0.3"
+ "@sinonjs/samsam" "^5.3.1"
diff "^4.0.2"
- nise "^4.0.1"
+ nise "^4.1.0"
supports-color "^7.1.0"
socket.io-adapter@~1.1.0:
@@ -3808,14 +3880,9 @@
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
- integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
+ integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
sshpk@^1.7.0:
version "1.16.1"
@@ -3856,30 +3923,14 @@
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
-string-width@^3.0.0, string-width@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
- integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+string-width@^4.1.0, string-width@^4.2.0:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
+ integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
dependencies:
- emoji-regex "^7.0.1"
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^5.1.0"
-
-string.prototype.trimend@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
- integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
-
-string.prototype.trimstart@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
- integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.0"
strip-ansi@^4.0.0:
version "4.0.0"
@@ -3888,29 +3939,36 @@
dependencies:
ansi-regex "^3.0.0"
-strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
+strip-ansi@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+ integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
+ dependencies:
+ ansi-regex "^5.0.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-json-comments@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+strip-json-comments@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-supports-color@6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
- integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
+supports-color@8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
- has-flag "^3.0.0"
+ has-flag "^4.0.0"
supports-color@^5.3.0:
version "5.5.0"
@@ -3920,28 +3978,28 @@
has-flag "^3.0.0"
supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
-systemjs@^6.3.1:
- version "6.3.3"
- resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.3.3.tgz#c0f2bec5cc72d0b36a8b971b1fa32bfc828b50d4"
- integrity sha512-djQ6mZ4/cWKnVnhAWvr/4+5r7QHnC7WiA8sS9VuYRdEv3wYZYTIIQv8zPT79PdDSUwfX3bgvu5mZ8eTyLm2YQA==
+systemjs@^6.3.1, systemjs@^6.8.3:
+ version "6.8.3"
+ resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.8.3.tgz#67e27f49242e9d81c2b652b204ae54e8bfcc75a3"
+ integrity sha512-UcTY+FEA1B7e+bpJk1TI+a9Na6LG7wFEqW7ED16cLqLuQfI/9Ri0rsXm3tKlIgNoHyLHZycjdAOijzNbzelgwA==
-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==
+table-layout@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04"
+ integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==
dependencies:
array-back "^4.0.1"
deep-extend "~0.6.0"
typical "^5.2.0"
wordwrapjs "^4.0.0"
-terser@^4.6.7:
+terser@^4.6.3, terser@^4.6.7:
version "4.8.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
@@ -4019,9 +4077,14 @@
punycode "^2.1.0"
tslib@^1.11.1:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
- integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.3:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
+ integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tsscmp@1.0.6:
version "1.0.6"
@@ -4058,16 +4121,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:
+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==
-uglify-js@^3.5.1:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.0.tgz#397a7e6e31ce820bfd1cb55b804ee140c587a9e7"
- integrity sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==
-
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
@@ -4106,15 +4164,10 @@
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
-upper-case@^1.1.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
- integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
-
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
@@ -4173,12 +4226,12 @@
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.1.0"
- resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.1.0.tgz#49d630cdfa308dba7f2819d49d09364f540dbcc6"
- integrity sha512-pgmbsVWKpH9GxLXZmtdowDIqtb/rvPyjjQv3z9wLcmgWKFHilKnZD3ldgrOlwJoPGOUluQsRPWd52yVkPfmI1A==
+whatwg-fetch@^3.0.0, whatwg-fetch@^3.5.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
+ integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
-whatwg-url@^7.0.0:
+whatwg-url@^7.0.0, whatwg-url@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
@@ -4187,12 +4240,14 @@
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@2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
-which@1.3.1, which@^1.2.1:
+which@^1.2.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -4212,21 +4267,26 @@
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
wordwrapjs@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.0.tgz#9aa9394155993476e831ba8e59fb5795ebde6800"
- integrity sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f"
+ integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==
dependencies:
reduce-flatten "^2.0.0"
- typical "^5.0.0"
+ typical "^5.2.0"
-wrap-ansi@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
- integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
+workerpool@6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b"
+ integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
- ansi-styles "^3.2.0"
- string-width "^3.0.0"
- strip-ansi "^5.0.0"
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
wrappy@1:
version "1.0.2"
@@ -4247,10 +4307,10 @@
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
-y18n@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
- integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yallist@^2.1.2:
version "2.1.2"
@@ -4262,38 +4322,43 @@
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"
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yargs-unparser@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
- integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==
- dependencies:
- flat "^4.1.0"
- lodash "^4.17.15"
- yargs "^13.3.0"
+yargs-parser@20.2.4:
+ version "20.2.4"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+ integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
-yargs@13.3.2, yargs@^13.3.0:
- version "13.3.2"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
- integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
+yargs-parser@^20.2.2:
+ version "20.2.7"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
+ integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
+
+yargs-unparser@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+ integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
dependencies:
- cliui "^5.0.0"
- find-up "^3.0.0"
- get-caller-file "^2.0.1"
+ camelcase "^6.0.0"
+ decamelize "^4.0.0"
+ flat "^5.0.2"
+ is-plain-obj "^2.1.0"
+
+yargs@16.2.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
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"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
yeast@0.1.2:
version "0.1.2"
@@ -4304,3 +4369,8 @@
version "1.2.1"
resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"
integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
diff --git a/proto/cache.proto b/proto/cache.proto
index 874e60a..292a225 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -286,6 +286,29 @@
repeated ExternalGroupProto external_group = 1;
}
+// Serialized key for com.google.gerrit.server.account.GroupCacheImpl.
+// Next ID: 3
+message GroupKeyProto {
+ string uuid = 1;
+ bytes revision = 2;
+}
+
+
+// Serialized form of com.google.gerrit.entities.InternalGroup.
+// Next ID: 11
+message InternalGroupProto {
+ int32 id = 1;
+ string name = 2;
+ string description = 3;
+ string owner_group_uuid = 4;
+ bool is_visible_to_all = 5;
+ string group_uuid = 6;
+ int64 created_on = 7;
+ repeated int32 members_ids = 8;
+ repeated string subgroup_uuids = 9;
+ bytes ref_state = 10;
+}
+
// Key for com.google.gerrit.server.git.PureRevertCache.
// Next ID: 4
message PureRevertKeyProto {
diff --git a/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html b/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
index 4923143..efd760f 100644
--- a/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
+++ b/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
@@ -75,11 +75,6 @@
<a href="?id=https://login.launchpad.net/%2Bopenid" id="id_launchpad">Sign in with a Launchpad ID</a>
</div>
- <div id="provider_yahoo">
- <img height="16" width="16" src="data:image/gif;base64,R0lGODlhEAAQAPECAAAAAP8AAP///8zMzCH5BAEAAAMALAAAAAAQABAAAAIqnI+py30BY3AgAjCkfJDjiIAQlgUkNxqWkqrm0honKk7KhZOzw/f+fygAADs=" />
- <a href="?id=https://me.yahoo.com" id="id_yahoo">Sign in with a Yahoo! ID</a>
- </div>
-
<div style="margin-top: 25px;">
<h2>What is OpenID?</h2>
<p>OpenID provides secure single-sign-on, without revealing your passwords to this website.</p>
diff --git a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
index 93584c6..11717fb 100644
--- a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
+++ b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
@@ -107,6 +107,7 @@
<link rel="preload" href="{$staticResourcePath}/bower_components/highlightjs/highlight.min.js" as="script"/>
{/if}
<link rel="preload" href="{$canonicalPath}/{$changeRequestsPath}/comments" as="fetch" type="application/json" crossorigin="anonymous"/>{\n}
+ <link rel="preload" href="{$canonicalPath}/{$changeRequestsPath}/comments?enable-context=true&context-padding=3" as="fetch" type="application/json" crossorigin="anonymous"/>{\n}
<link rel="preload" href="{$canonicalPath}/{$changeRequestsPath}/robotcomments" as="fetch" type="application/json" crossorigin="anonymous"/>{\n}
{if $userIsAuthenticated}
<link rel="preload" href="{$canonicalPath}/{$changeRequestsPath}/drafts" as="fetch" type="application/json" crossorigin="anonymous"/>{\n}
diff --git a/resources/com/google/gerrit/server/config/CapabilityConstants.properties b/resources/com/google/gerrit/server/config/CapabilityConstants.properties
index ba590ee..1a355eb 100644
--- a/resources/com/google/gerrit/server/config/CapabilityConstants.properties
+++ b/resources/com/google/gerrit/server/config/CapabilityConstants.properties
@@ -15,9 +15,9 @@
runAs = Run As
runGC = Run Garbage Collection
streamEvents = Stream Events
+viewAccess = View Access
viewAllAccounts = View All Accounts
viewCaches = View Caches
viewConnections = View Connections
viewPlugins = View Plugins
viewQueue = View Queue
-viewAccess = View Access
diff --git a/resources/com/google/gerrit/server/mail/Abandoned.soy b/resources/com/google/gerrit/server/mail/Abandoned.soy
index b57f00a..9148fa1 100644
--- a/resources/com/google/gerrit/server/mail/Abandoned.soy
+++ b/resources/com/google/gerrit/server/mail/Abandoned.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Abandoned}
/**
* The .Abandoned template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/AbandonedHtml.soy b/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
index 9f80241..b4e5de8 100644
--- a/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.AbandonedHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/AddKey.soy b/resources/com/google/gerrit/server/mail/AddKey.soy
index c77ab56..319db05 100644
--- a/resources/com/google/gerrit/server/mail/AddKey.soy
+++ b/resources/com/google/gerrit/server/mail/AddKey.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.AddKey}
import * as mailTemplate from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
diff --git a/resources/com/google/gerrit/server/mail/AddKeyHtml.soy b/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
index 3987684..c356a95 100644
--- a/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.AddKeyHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/NoReplyFooterHtml.soy';
diff --git a/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy b/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
index 64c1ad3..fcadb55 100644
--- a/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
+++ b/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.AddToAttentionSet}
/**
* The .AddToAttentionSet template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy b/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
index 04d759e..f550bb1 100644
--- a/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.AddToAttentionSetHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/ChangeFooter.soy b/resources/com/google/gerrit/server/mail/ChangeFooter.soy
index 236b171..c5b9e4a 100644
--- a/resources/com/google/gerrit/server/mail/ChangeFooter.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeFooter.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ChangeFooter}
/**
* The .ChangeFooter template will determine the contents of the footer text
diff --git a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
index 28442ee..5a22acb 100644
--- a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ChangeFooterHtml}
{template ChangeFooterHtml}
{@param change: ?}
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeader.soy b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
index 7a2da65..5dfe671 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeader.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ChangeHeader}
{template ChangeHeader kind="text"}
{@param attentionSet: ?}
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
index a1bcd8f..191737f 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
@@ -15,7 +15,7 @@
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ChangeHeaderHtml}
{template ChangeHeaderHtml}
{@param attentionSet: ?}
diff --git a/resources/com/google/gerrit/server/mail/ChangeSubject.soy b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
index 12422ed..28d04d0 100644
--- a/resources/com/google/gerrit/server/mail/ChangeSubject.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ChangeSubject}
/**
* The .ChangeSubject template will determine the contents of the email subject
diff --git a/resources/com/google/gerrit/server/mail/Comment.soy b/resources/com/google/gerrit/server/mail/Comment.soy
index 973b369..4b923e6 100644
--- a/resources/com/google/gerrit/server/mail/Comment.soy
+++ b/resources/com/google/gerrit/server/mail/Comment.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Comment}
/**
* The .Comment template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/CommentFooter.soy b/resources/com/google/gerrit/server/mail/CommentFooter.soy
index 3c111f7..854687c 100644
--- a/resources/com/google/gerrit/server/mail/CommentFooter.soy
+++ b/resources/com/google/gerrit/server/mail/CommentFooter.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.CommentFooter}
/**
* The .CommentFooter template will determine the contents of the footer text
diff --git a/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy b/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
index ce8a933..cad0973 100644
--- a/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.CommentFooterHtml}
{template CommentFooterHtml}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/CommentHtml.soy b/resources/com/google/gerrit/server/mail/CommentHtml.soy
index b3924c3..a120cea 100644
--- a/resources/com/google/gerrit/server/mail/CommentHtml.soy
+++ b/resources/com/google/gerrit/server/mail/CommentHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.CommentHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/DeleteKey.soy b/resources/com/google/gerrit/server/mail/DeleteKey.soy
index ffc12dc..0957dc6 100644
--- a/resources/com/google/gerrit/server/mail/DeleteKey.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteKey.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteKey}
/**
* The .DeleteKey template will determine the contents of the email related to
diff --git a/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy b/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
index 4ce5246..fea6785 100644
--- a/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteKeyHtml}
{template DeleteKeyHtml}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
index a9ba802..a3ed3ee 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteReviewer}
/**
* The .DeleteReviewer template will determine the contents of the email related
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
index 685ca4c..76a9199 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteReviewerHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/DeleteVote.soy b/resources/com/google/gerrit/server/mail/DeleteVote.soy
index 74790f7..c2e3e6d 100644
--- a/resources/com/google/gerrit/server/mail/DeleteVote.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteVote.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteVote}
/**
* The .DeleteVote template will determine the contents of the email related
diff --git a/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy b/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
index dd3b423..bff9212 100644
--- a/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.DeleteVoteHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/Footer.soy b/resources/com/google/gerrit/server/mail/Footer.soy
index 6ce0d3b..fc1952f 100644
--- a/resources/com/google/gerrit/server/mail/Footer.soy
+++ b/resources/com/google/gerrit/server/mail/Footer.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Footer}
/**
* The .Footer template will determine the contents of the footer text
diff --git a/resources/com/google/gerrit/server/mail/FooterHtml.soy b/resources/com/google/gerrit/server/mail/FooterHtml.soy
index c89dea7..9a36837 100644
--- a/resources/com/google/gerrit/server/mail/FooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/FooterHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.FooterHtml}
{template FooterHtml}
{@param footers: ?}
diff --git a/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy b/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
index 08daa932..49fbccb 100644
--- a/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
+++ b/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.HttpPasswordUpdate}
/**
* The .HttpPasswordUpdate template will determine the contents of the email related to
diff --git a/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy b/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
index e28aaaa..3f88a6f 100644
--- a/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
+++ b/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.HttpPasswordUpdateHtml}
{template HttpPasswordUpdateHtml}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy b/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
index 378785a..1241665 100644
--- a/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
+++ b/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.InboundEmailRejection}
import * as noReplyFooter from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
diff --git a/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy b/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
index f0b18d2..6937d13 100644
--- a/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
+++ b/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.InboundEmailRejectionHtml}
import * as noReplyFooter from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
import * as noReplyFooterHtml from 'com/google/gerrit/server/mail/NoReplyFooterHtml.soy';
diff --git a/resources/com/google/gerrit/server/mail/Merged.soy b/resources/com/google/gerrit/server/mail/Merged.soy
index b586851..998610c 100644
--- a/resources/com/google/gerrit/server/mail/Merged.soy
+++ b/resources/com/google/gerrit/server/mail/Merged.soy
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Merged}
/**
* The .Merged template will determine the contents of the email related to
diff --git a/resources/com/google/gerrit/server/mail/MergedHtml.soy b/resources/com/google/gerrit/server/mail/MergedHtml.soy
index 53c1645..1f75a04 100644
--- a/resources/com/google/gerrit/server/mail/MergedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/MergedHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.MergedHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/NewChange.soy b/resources/com/google/gerrit/server/mail/NewChange.soy
index fe99ba4..0fe8835 100644
--- a/resources/com/google/gerrit/server/mail/NewChange.soy
+++ b/resources/com/google/gerrit/server/mail/NewChange.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.NewChange}
/**
* The .NewChange template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
index 756d6ce..dbb3d8a 100644
--- a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
+++ b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.NewChangeHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/NoReplyFooter.soy b/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
index d309e90..304a5bc 100644
--- a/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
+++ b/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.NoReplyFooter}
{template NoReplyFooter kind="text"}
{\n}
diff --git a/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy b/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
index 1baf5ab..6d2103c 100644
--- a/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.NoReplyFooterHtml}
{template NoReplyFooterHtml}
<p>
diff --git a/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy b/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
index bde8152..273f52f 100644
--- a/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
+++ b/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RegisterNewEmail}
/**
* The .RegisterNewEmail template will determine the contents of the email
diff --git a/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy b/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
index e3ec3a5..7d6cd23 100644
--- a/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RegisterNewEmailHtml}
{template RegisterNewEmailHtml}
{@param email: ?}
@@ -45,4 +45,4 @@
This is a send-only email address. Replies to this message will not
be read or answered.
</p>
-{/template}
\ No newline at end of file
+{/template}
diff --git a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
index a329f7b..b33f908 100644
--- a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
+++ b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RemoveFromAttentionSet}
/**
* The .RemoveFromAttentionSet template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
index c1c6185..b27fef8 100644
--- a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RemoveFromAttentionSetHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy b/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
index 6dffa6b..2647572 100644
--- a/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
+++ b/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ReplacePatchSet}
/**
* The .ReplacePatchSet template will determine the contents of the email
diff --git a/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy b/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
index 57c6db6..4916a4a 100644
--- a/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.ReplacePatchSetHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/Restored.soy b/resources/com/google/gerrit/server/mail/Restored.soy
index e09f95f..6bc76ee 100644
--- a/resources/com/google/gerrit/server/mail/Restored.soy
+++ b/resources/com/google/gerrit/server/mail/Restored.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Restored}
/**
* The .Restored template will determine the contents of the email related to a
diff --git a/resources/com/google/gerrit/server/mail/RestoredHtml.soy b/resources/com/google/gerrit/server/mail/RestoredHtml.soy
index 19c4b99..49e8924 100644
--- a/resources/com/google/gerrit/server/mail/RestoredHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RestoredHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RestoredHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/Reverted.soy b/resources/com/google/gerrit/server/mail/Reverted.soy
index bdfd0ad..15a5fb7 100644
--- a/resources/com/google/gerrit/server/mail/Reverted.soy
+++ b/resources/com/google/gerrit/server/mail/Reverted.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.Reverted}
/**
* The .Reverted template will determine the contents of the email related
diff --git a/resources/com/google/gerrit/server/mail/RevertedHtml.soy b/resources/com/google/gerrit/server/mail/RevertedHtml.soy
index d7b60df..8bc911b 100644
--- a/resources/com/google/gerrit/server/mail/RevertedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RevertedHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.RevertedHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/com/google/gerrit/server/mail/SetAssignee.soy b/resources/com/google/gerrit/server/mail/SetAssignee.soy
index 5e83cfb..83aa580 100644
--- a/resources/com/google/gerrit/server/mail/SetAssignee.soy
+++ b/resources/com/google/gerrit/server/mail/SetAssignee.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.SetAssignee}
/**
* The .SetAssignee template will determine the contents of the email related
diff --git a/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy b/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
index 4ff6cc1..5435cab 100644
--- a/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
+++ b/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-{namespace com.google.gerrit.server.mail.template}
+{namespace com.google.gerrit.server.mail.template.SetAssigneeHtml}
import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
diff --git a/resources/log4j.properties b/resources/log4j.properties
index 28c0ee4..2898cfc 100644
--- a/resources/log4j.properties
+++ b/resources/log4j.properties
@@ -21,6 +21,7 @@
# Silence non-critical messages from MINA SSHD.
#
log4j.logger.org.apache.mina=WARN
+log4j.logger.org.apache.sshd.client=WARN
log4j.logger.org.apache.sshd.common=WARN
log4j.logger.org.apache.sshd.server=WARN
log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO
@@ -40,11 +41,5 @@
log4j.logger.org.openid4java.server.RealmVerifier=ERROR
log4j.logger.org.openid4java.message.AuthSuccess=ERROR
-# Silence non-critical messages from c3p0 (if used).
-#
-log4j.logger.com.mchange.v2.c3p0=WARN
-log4j.logger.com.mchange.v2.resourcepool=WARN
-log4j.logger.com.mchange.v2.sql=WARN
-
# Silence non-critical messages from apache.http
log4j.logger.org.apache.http=WARN
diff --git a/tools/bzl/js.bzl b/tools/bzl/js.bzl
index bbb1432..facb1ce 100644
--- a/tools/bzl/js.bzl
+++ b/tools/bzl/js.bzl
@@ -455,22 +455,8 @@
if not plugin_name:
plugin_name = name
- html_plugin = app.endswith(".html")
srcs = srcs if app in srcs else srcs + [app]
-
- if html_plugin:
- # Combines all .js and .html files into foo_combined.js and foo_combined.html
- _bundle_rule(
- name = name + "_combined",
- app = app,
- srcs = srcs,
- deps = deps,
- pkg = native.package_name(),
- **kwargs
- )
- js_srcs = [name + "_combined.js"]
- else:
- js_srcs = srcs
+ js_srcs = srcs
native.filegroup(
name = name + "-src-fg",
@@ -483,25 +469,6 @@
src = name + "-src-fg",
)
- if html_plugin:
- native.genrule(
- name = name + "_rename_html",
- srcs = [name + "_combined.html"],
- outs = [plugin_name + ".html"],
- cmd = "sed 's/<script src=\"" + name + "_combined.js\"/<script src=\"" + plugin_name + ".js\"/g' $(SRCS) > $(OUTS)",
- output_to_bindir = True,
- )
- else:
- # For polymer 3 migration, we will only have js plugins, in case server side
- # is still asking for *.html, we still want to create a html placeholder just to load the js
- # TODO(taoalpha): this should be cleaned up once polymer 3 plugins are the only ones gerrit supports
- native.genrule(
- name = name + "_rename_html",
- outs = [plugin_name + ".html"],
- cmd = "echo \"<script src='" + plugin_name + ".js'></script>\" > $(OUTS)",
- output_to_bindir = True,
- )
-
native.genrule(
name = name + "_rename_js",
srcs = [name + ".min"],
@@ -510,7 +477,7 @@
output_to_bindir = True,
)
- static_files = [plugin_name + ".js", plugin_name + ".html"]
+ static_files = [plugin_name + ".js"]
if assets:
nested, direct = [], []
diff --git a/tools/eclipse/project.py b/tools/eclipse/project.py
index acb5346..c7398a8 100755
--- a/tools/eclipse/project.py
+++ b/tools/eclipse/project.py
@@ -188,6 +188,8 @@
classpathentry('src', 'modules/jgit/org.eclipse.jgit.junit/src')
classpathentry('src', 'modules/jgit/org.eclipse.jgit.ssh.jsch/src')
classpathentry('src', 'modules/jgit/org.eclipse.jgit.ssh.jsch/resources')
+ classpathentry('src', 'modules/jgit/org.eclipse.jgit.ssh.apache/src')
+ classpathentry('src', 'modules/jgit/org.eclipse.jgit.ssh.apache/resources')
def classpathentry(kind, path, src=None, out=None, exported=None, excluding=None):
e = doc.createElement('classpathentry')
diff --git a/tools/maven/gerrit-acceptance-framework_pom.xml b/tools/maven/gerrit-acceptance-framework_pom.xml
index 718f8d0..3705407 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.4.0-SNAPSHOT</version>
+ <version>3.5.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 a415f24..ba35ca2 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.4.0-SNAPSHOT</version>
+ <version>3.5.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 5e58fdd..b7954c7 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.4.0-SNAPSHOT</version>
+ <version>3.5.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 3b3a055..118cf39 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.4.0-SNAPSHOT</version>
+ <version>3.5.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Gerrit Code Review - WAR</name>
<description>Gerrit WAR</description>
diff --git a/tools/node_tools/node_modules_licenses/utils.ts b/tools/node_tools/node_modules_licenses/utils.ts
index 5f8e7b3..e73bf96 100644
--- a/tools/node_tools/node_modules_licenses/utils.ts
+++ b/tools/node_tools/node_modules_licenses/utils.ts
@@ -22,6 +22,15 @@
process.exit(1);
}
+// Bazel params may be surrounded with quotes
+function removeSurrondedQuotes(str: string): string {
+ return str.startsWith("'") && str.endsWith("'") ?
+ str.slice(1, -1) : str;
+}
+
export function readMultilineParamFile(path: string): string[] {
- return fs.readFileSync(path, {encoding: 'utf-8'}).split(/\r?\n/).filter(f => f.length > 0);
+ return fs.readFileSync(path, {encoding: 'utf-8'})
+ .split(/\r?\n/)
+ .filter(f => f.length > 0)
+ .map(removeSurrondedQuotes);
}
diff --git a/tools/node_tools/package.json b/tools/node_tools/package.json
index 9acbd07..6e29299 100644
--- a/tools/node_tools/package.json
+++ b/tools/node_tools/package.json
@@ -3,8 +3,8 @@
"description": "Gerrit Build Tools",
"browser": false,
"dependencies": {
- "@bazel/rollup": "^3.2.0",
- "@bazel/typescript": "^3.2.0",
+ "@bazel/rollup": "^3.4.0",
+ "@bazel/typescript": "^3.4.0",
"@types/node": "^10.17.12",
"@types/parse5": "^4.0.0",
"@types/parse5-html-rewriting-stream": "^5.1.2",
@@ -16,7 +16,7 @@
"rollup": "^2.3.4",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^5.1.3",
- "typescript": "4.0.5"
+ "typescript": "4.1.4"
},
"devDependencies": {},
"license": "Apache-2.0",
diff --git a/tools/node_tools/yarn.lock b/tools/node_tools/yarn.lock
index 45a0c89..b8ac5fb 100644
--- a/tools/node_tools/yarn.lock
+++ b/tools/node_tools/yarn.lock
@@ -492,15 +492,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
-"@bazel/rollup@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.2.0.tgz#4241a5767e12e57b01279a539af2537c2d01924a"
- integrity sha512-Wkw6L+hor/+FzpDswri7IlWAbKyShnUZRx59fG06+qqVhpNaS3V3lnZqVytMlLLT4oSP8YSIzoXC5GkXgLI2/Q==
+"@bazel/rollup@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.4.0.tgz#cdecb2b90535ef51fb3d56cc8bc19996918bac1a"
+ integrity sha512-QKnttbYyEQjRbWrOlkH2JuDnSww+9K7Ppil91zBTtr/qYTGW9XO0v7Ft3cs30s2NIWSGIuKj9/N5as+Uyratrw==
-"@bazel/typescript@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.2.0.tgz#299bd173fe04f98407ab9be4f654662c1c28470e"
- integrity sha512-RKdy9ThbcUAqZR3AJK7AR/nxbJqdHi7pPayIGUSMIpxVkeTxVRQpf1aGe2H02HdZ9fR/uk1xXhO/Ff9TLvTgHQ==
+"@bazel/typescript@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.0.tgz#031d989682ff8605ed8745f31448c2f76a1b653a"
+ integrity sha512-XlWrlQnsdQHTwsliUAf4mySHOgqRY2S57LKG2rKRjm+a015Lzlmxo6jRQaxjr68UmuhmlklRw0WfCFxdR81AvQ==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
@@ -7893,10 +7893,10 @@
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389"
- integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==
+typescript@4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.4.tgz#f058636e2f4f83f94ddaae07b20fd5e14598432f"
+ integrity sha512-+Uru0t8qIRgjuCpiSPpfGuhHecMllk5Zsazj5LZvVsEStEjmIRRBZe+jHjGQvsgS7M1wONy2PQXd67EMyV6acg==
typical@^2.6.0, typical@^2.6.1:
version "2.6.1"
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index 3f5ef20..3d04592 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -44,6 +44,12 @@
)
maven_jar(
+ name = "sshd-sftp",
+ artifact = "org.apache.sshd:sshd-sftp:" + SSHD_VERS,
+ sha1 = "6eddfe8fdf59a3d9a49151e4177f8c1bebeb30c9",
+ )
+
+ maven_jar(
name = "eddsa",
artifact = "net.i2p.crypto:eddsa:0.3.0",
sha1 = "1901c8d4d8bffb7d79027686cfb91e704217c3e1",
@@ -141,24 +147,24 @@
sha1 = GUAVA_BIN_SHA1,
)
- GUICE_VERS = "5.0.0-BETA-1"
+ GUICE_VERS = "5.0.1"
maven_jar(
name = "guice-library",
artifact = "com.google.inject:guice:" + GUICE_VERS,
- sha1 = "c5572be8a8b75ea50e0fdf54fa1f75a3141ab936",
+ sha1 = "0dae7556b441cada2b4f0a2314eb68e1ff423429",
)
maven_jar(
name = "guice-assistedinject",
artifact = "com.google.inject.extensions:guice-assistedinject:" + GUICE_VERS,
- sha1 = "4d06eba0e08151b52d9e25a14e4f01eedf998bc3",
+ sha1 = "62e02f2aceb7d90ba354584dacc018c1e94ff01c",
)
maven_jar(
name = "guice-servlet",
artifact = "com.google.inject.extensions:guice-servlet:" + GUICE_VERS,
- sha1 = "373b9a4f1b6683d9a991410660d2c9adb9f06737",
+ sha1 = "f527009d51f172a2e6937bfb55fcb827e2e2386b",
)
# Keep this version of Soy synchronized with the version used in Gitiles.
diff --git a/tools/remote-bazelrc b/tools/remote-bazelrc
index 22ee330..78b86d2 100644
--- a/tools/remote-bazelrc
+++ b/tools/remote-bazelrc
@@ -25,7 +25,7 @@
# this higher can make builds faster by allowing more jobs to run in parallel.
# Setting it too high can result in jobs that timeout, however, while waiting
# for a remote machine to execute them.
-build:remote --jobs=100
+build:remote --jobs=200
build:remote --disk_cache=
# Set several flags related to specifying the platform, toolchain and java
@@ -57,7 +57,7 @@
# Enable authentication. This will pick up application default credentials by
# default. You can use --auth_credentials=some_file.json to use a service
# account credential instead.
-build:remote --auth_enabled=true
+build:remote --google_default_credentials
# The following flags enable the remote cache so action results can be shared
# across machines, developers, and workspaces.
diff --git a/version.bzl b/version.bzl
index 066d07e..f2e0d0c 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.4.0-SNAPSHOT"
+GERRIT_VERSION = "3.5.0-SNAPSHOT"
diff --git a/yarn.lock b/yarn.lock
index a424d79..ead8dbf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,513 +2,537 @@
# yarn lockfile v1
-"@babel/code-frame@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
- integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
+"@babel/code-frame@7.12.11", "@babel/code-frame@^7.0.0":
+ version "7.12.11"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"
+ integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
- "@babel/highlight" "^7.0.0"
+ "@babel/highlight" "^7.10.4"
+
+"@babel/code-frame@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
+ integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
+ dependencies:
+ "@babel/highlight" "^7.12.13"
+
+"@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8":
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4"
+ integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==
"@babel/core@^7.0.0":
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd"
- integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ==
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.15.tgz#a6d40917df027487b54312202a06812c4f7792d0"
+ integrity sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==
dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.5.0"
- "@babel/helpers" "^7.5.4"
- "@babel/parser" "^7.5.0"
- "@babel/template" "^7.4.4"
- "@babel/traverse" "^7.5.0"
- "@babel/types" "^7.5.0"
- convert-source-map "^1.1.0"
+ "@babel/code-frame" "^7.12.13"
+ "@babel/generator" "^7.13.9"
+ "@babel/helper-compilation-targets" "^7.13.13"
+ "@babel/helper-module-transforms" "^7.13.14"
+ "@babel/helpers" "^7.13.10"
+ "@babel/parser" "^7.13.15"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.15"
+ "@babel/types" "^7.13.14"
+ convert-source-map "^1.7.0"
debug "^4.1.0"
- json5 "^2.1.0"
- lodash "^4.17.11"
- resolve "^1.3.2"
- semver "^5.4.1"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.1.2"
+ semver "^6.3.0"
source-map "^0.5.0"
-"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.5.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a"
- integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA==
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.13.9":
+ version "7.13.9"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
+ integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
dependencies:
- "@babel/types" "^7.5.0"
+ "@babel/types" "^7.13.0"
jsesc "^2.5.1"
- lodash "^4.17.11"
source-map "^0.5.0"
- trim-right "^1.0.1"
-"@babel/helper-annotate-as-pure@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
- integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==
+"@babel/helper-annotate-as-pure@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
+ integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.12.13"
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f"
- integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc"
+ integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==
dependencies:
- "@babel/helper-explode-assignable-expression" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/helper-explode-assignable-expression" "^7.12.13"
+ "@babel/types" "^7.12.13"
-"@babel/helper-call-delegate@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43"
- integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==
+"@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8":
+ version "7.13.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5"
+ integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==
dependencies:
- "@babel/helper-hoist-variables" "^7.4.4"
- "@babel/traverse" "^7.4.4"
- "@babel/types" "^7.4.4"
+ "@babel/compat-data" "^7.13.12"
+ "@babel/helper-validator-option" "^7.12.17"
+ browserslist "^4.14.5"
+ semver "^6.3.0"
-"@babel/helper-define-map@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
- integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
+"@babel/helper-create-regexp-features-plugin@^7.12.13":
+ version "7.12.17"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7"
+ integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==
dependencies:
- "@babel/helper-function-name" "^7.1.0"
- "@babel/types" "^7.4.4"
- lodash "^4.17.11"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ regexpu-core "^4.7.1"
-"@babel/helper-explode-assignable-expression@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6"
- integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==
+"@babel/helper-explode-assignable-expression@^7.12.13":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f"
+ integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==
dependencies:
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.13.0"
-"@babel/helper-function-name@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
- integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
+"@babel/helper-function-name@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a"
+ integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==
dependencies:
- "@babel/helper-get-function-arity" "^7.0.0"
- "@babel/template" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/helper-get-function-arity" "^7.12.13"
+ "@babel/template" "^7.12.13"
+ "@babel/types" "^7.12.13"
-"@babel/helper-get-function-arity@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
- integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==
+"@babel/helper-get-function-arity@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
+ integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.12.13"
-"@babel/helper-hoist-variables@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
- integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==
+"@babel/helper-member-expression-to-functions@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
+ integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==
dependencies:
- "@babel/types" "^7.4.4"
+ "@babel/types" "^7.13.12"
-"@babel/helper-member-expression-to-functions@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f"
- integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==
+"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
+ integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.13.12"
-"@babel/helper-module-imports@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
- integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
+"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef"
+ integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/helper-module-imports" "^7.13.12"
+ "@babel/helper-replace-supers" "^7.13.12"
+ "@babel/helper-simple-access" "^7.13.12"
+ "@babel/helper-split-export-declaration" "^7.12.13"
+ "@babel/helper-validator-identifier" "^7.12.11"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.13"
+ "@babel/types" "^7.13.14"
-"@babel/helper-module-transforms@^7.1.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
- integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
+"@babel/helper-optimise-call-expression@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea"
+ integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==
dependencies:
- "@babel/helper-module-imports" "^7.0.0"
- "@babel/helper-simple-access" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.4.4"
- "@babel/template" "^7.4.4"
- "@babel/types" "^7.4.4"
- lodash "^4.17.11"
+ "@babel/types" "^7.12.13"
-"@babel/helper-optimise-call-expression@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5"
- integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==
+"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
+ integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
+
+"@babel/helper-remap-async-to-generator@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
+ integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==
dependencies:
- "@babel/types" "^7.0.0"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ "@babel/helper-wrap-function" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/helper-plugin-utils@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
- integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
-
-"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
- integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
+"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804"
+ integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==
dependencies:
- lodash "^4.17.11"
+ "@babel/helper-member-expression-to-functions" "^7.13.12"
+ "@babel/helper-optimise-call-expression" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.12"
-"@babel/helper-remap-async-to-generator@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f"
- integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==
+"@babel/helper-simple-access@^7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6"
+ integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.0.0"
- "@babel/helper-wrap-function" "^7.1.0"
- "@babel/template" "^7.1.0"
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.13.12"
-"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
- integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
+"@babel/helper-skip-transparent-expression-wrappers@^7.12.1":
+ version "7.12.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf"
+ integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==
dependencies:
- "@babel/helper-member-expression-to-functions" "^7.0.0"
- "@babel/helper-optimise-call-expression" "^7.0.0"
- "@babel/traverse" "^7.4.4"
- "@babel/types" "^7.4.4"
+ "@babel/types" "^7.12.1"
-"@babel/helper-simple-access@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
- integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==
+"@babel/helper-split-export-declaration@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05"
+ integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==
dependencies:
- "@babel/template" "^7.1.0"
- "@babel/types" "^7.0.0"
+ "@babel/types" "^7.12.13"
-"@babel/helper-split-export-declaration@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
- integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
- dependencies:
- "@babel/types" "^7.4.4"
+"@babel/helper-validator-identifier@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz"
+ integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
-"@babel/helper-wrap-function@^7.1.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
- integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==
- dependencies:
- "@babel/helper-function-name" "^7.1.0"
- "@babel/template" "^7.1.0"
- "@babel/traverse" "^7.1.0"
- "@babel/types" "^7.2.0"
+"@babel/helper-validator-option@^7.12.17":
+ version "7.12.17"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831"
+ integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==
-"@babel/helpers@^7.5.4":
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0"
- integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow==
+"@babel/helper-wrap-function@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
+ integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==
dependencies:
- "@babel/template" "^7.4.4"
- "@babel/traverse" "^7.5.0"
- "@babel/types" "^7.5.0"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.0"
-"@babel/highlight@^7.0.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
- integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+"@babel/helpers@^7.13.10":
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
+ integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
dependencies:
+ "@babel/template" "^7.12.13"
+ "@babel/traverse" "^7.13.0"
+ "@babel/types" "^7.13.0"
+
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13":
+ version "7.13.10"
+ resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz"
+ integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.12.11"
chalk "^2.0.0"
- esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.4.4", "@babel/parser@^7.5.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7"
- integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA==
+"@babel/parser@^7.12.13", "@babel/parser@^7.13.15":
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8"
+ integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==
"@babel/plugin-external-helpers@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4"
- integrity sha512-QFmtcCShFkyAsNtdCM3lJPmRe1iB+vPZymlB4LnDIKEBj2yKQLQKtoxXxJ8ePT5fwMl4QGg303p4mB0UsSI2/g==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.12.13.tgz#65ef9f4576297250dc601d2aa334769790d9966d"
+ integrity sha512-ClvAsk4RqpE6iacYUjdU9PtvIwC9yAefZENsPfGeG5FckX3jFZLDlWPuyv5gi9/9C2VgwX6H8q1ukBifC0ha+Q==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-proposal-async-generator-functions@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
- integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz#80e549df273a3b3050431b148c892491df1bcc5b"
+ integrity sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-remap-async-to-generator" "^7.1.0"
- "@babel/plugin-syntax-async-generators" "^7.2.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-remap-async-to-generator" "^7.13.0"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
"@babel/plugin-proposal-object-rest-spread@^7.0.0":
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
- integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
+ version "7.13.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a"
+ integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
+ "@babel/compat-data" "^7.13.8"
+ "@babel/helper-compilation-targets" "^7.13.8"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.13.0"
-"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f"
- integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.4":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+ integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-dynamic-import@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612"
- integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==
+ 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.0.0"
+ "@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-import-meta@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.2.0.tgz#2333ef4b875553a3bcd1e93f8ebc09f5b9213a40"
- integrity sha512-Hq6kFSZD7+PHkmBN8bCpHR6J8QEoCuEV/B38AIQscYjgMZkGlXB7cHNFzP5jR4RCh5545yP1ujHdmO7hAgKtBA==
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
- integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ 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"
+ integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-transform-arrow-functions@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550"
- integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae"
+ integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-async-to-generator@^7.0.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e"
- integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f"
+ integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==
dependencies:
- "@babel/helper-module-imports" "^7.0.0"
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-remap-async-to-generator" "^7.1.0"
+ "@babel/helper-module-imports" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-remap-async-to-generator" "^7.13.0"
"@babel/plugin-transform-block-scoped-functions@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190"
- integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4"
+ integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-block-scoping@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d"
- integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61"
+ integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- lodash "^4.17.11"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-classes@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6"
- integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz#0265155075c42918bf4d3a4053134176ad9b533b"
+ integrity sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.0.0"
- "@babel/helper-define-map" "^7.4.4"
- "@babel/helper-function-name" "^7.1.0"
- "@babel/helper-optimise-call-expression" "^7.0.0"
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.4.4"
- "@babel/helper-split-export-declaration" "^7.4.4"
+ "@babel/helper-annotate-as-pure" "^7.12.13"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-optimise-call-expression" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-replace-supers" "^7.13.0"
+ "@babel/helper-split-export-declaration" "^7.12.13"
globals "^11.1.0"
"@babel/plugin-transform-computed-properties@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da"
- integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed"
+ integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-destructuring@^7.0.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a"
- integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963"
+ integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-duplicate-keys@^7.0.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853"
- integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de"
+ integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-exponentiation-operator@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008"
- integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1"
+ integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==
dependencies:
- "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0"
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-for-of@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556"
- integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062"
+ integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-function-name@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad"
- integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051"
+ integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==
dependencies:
- "@babel/helper-function-name" "^7.1.0"
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-instanceof@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.2.0.tgz#2ee9dc9b389fa13cf325be10ff8414be0d10aecf"
- integrity sha512-tw2fb96tpcd5XaJXns19tGKo/SeIUS0exAteHJ/7EP27Bke7RmV/gAftHCf1WKZgKeZOUfzOL7nrXH2HIH9auA==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.12.13.tgz#5df8ead82ed421b728662c9e0ed943536c872ced"
+ integrity sha512-lYZ6F2xmM797Nk8PzDn2AreAEjKb96S3JkZkaMUlRTIThaYjvo1+aLa7oegnVc42lJY7Hr4yT1M/i6kwRcPlsQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-literals@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1"
- integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9"
+ integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-modules-amd@^7.0.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91"
- integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3"
+ integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==
dependencies:
- "@babel/helper-module-transforms" "^7.1.0"
- "@babel/helper-plugin-utils" "^7.0.0"
- babel-plugin-dynamic-import-node "^2.3.0"
+ "@babel/helper-module-transforms" "^7.13.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-object-super@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598"
- integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7"
+ integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-replace-supers" "^7.1.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
+ "@babel/helper-replace-supers" "^7.12.13"
-"@babel/plugin-transform-parameters@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16"
- integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==
+"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.13.0":
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz#8fa7603e3097f9c0b7ca1a4821bc2fb52e9e5007"
+ integrity sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==
dependencies:
- "@babel/helper-call-delegate" "^7.4.4"
- "@babel/helper-get-function-arity" "^7.0.0"
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-regenerator@^7.0.0":
- version "7.4.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f"
- integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39"
+ integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==
dependencies:
- regenerator-transform "^0.14.0"
+ regenerator-transform "^0.14.2"
"@babel/plugin-transform-shorthand-properties@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0"
- integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad"
+ integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-spread@^7.0.0":
- version "7.2.2"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406"
- integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd"
+ integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
"@babel/plugin-transform-sticky-regex@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1"
- integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f"
+ integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-regex" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-template-literals@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0"
- integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d"
+ integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.0.0"
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.13.0"
"@babel/plugin-transform-typeof-symbol@^7.0.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2"
- integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f"
+ integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/helper-plugin-utils" "^7.12.13"
"@babel/plugin-transform-unicode-regex@^7.0.0":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f"
- integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac"
+ integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==
dependencies:
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-regex" "^7.4.4"
- regexpu-core "^4.5.4"
+ "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.12.13"
-"@babel/template@^7.1.0", "@babel/template@^7.4.4":
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
- integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==
+"@babel/runtime@^7.8.4":
+ version "7.13.10"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
+ integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/parser" "^7.4.4"
- "@babel/types" "^7.4.4"
+ regenerator-runtime "^0.13.4"
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485"
- integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg==
+"@babel/template@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
+ integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==
dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.5.0"
- "@babel/helper-function-name" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.4.4"
- "@babel/parser" "^7.5.0"
- "@babel/types" "^7.5.0"
+ "@babel/code-frame" "^7.12.13"
+ "@babel/parser" "^7.12.13"
+ "@babel/types" "^7.12.13"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15":
+ version "7.13.15"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7"
+ integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@babel/generator" "^7.13.9"
+ "@babel/helper-function-name" "^7.12.13"
+ "@babel/helper-split-export-declaration" "^7.12.13"
+ "@babel/parser" "^7.13.15"
+ "@babel/types" "^7.13.14"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.11"
-"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.42", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0":
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab"
- integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ==
+"@babel/types@^7.0.0-beta.42", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
+ integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
dependencies:
- esutils "^2.0.2"
- lodash "^4.17.11"
+ "@babel/helper-validator-identifier" "^7.12.11"
+ lodash "^4.17.19"
to-fast-properties "^2.0.0"
-"@bazel/rollup@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.2.0.tgz#4241a5767e12e57b01279a539af2537c2d01924a"
- integrity sha512-Wkw6L+hor/+FzpDswri7IlWAbKyShnUZRx59fG06+qqVhpNaS3V3lnZqVytMlLLT4oSP8YSIzoXC5GkXgLI2/Q==
+"@bazel/rollup@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.4.0.tgz#cdecb2b90535ef51fb3d56cc8bc19996918bac1a"
+ integrity sha512-QKnttbYyEQjRbWrOlkH2JuDnSww+9K7Ppil91zBTtr/qYTGW9XO0v7Ft3cs30s2NIWSGIuKj9/N5as+Uyratrw==
-"@bazel/terser@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-3.2.0.tgz#e53ad32733a0b231323b9eb55ebc2a3c65b10223"
- integrity sha512-/yq4gST3t1mETkP6NjC05yEyIIL//4mbfLI56hE3CC/mm/xJ6UeooFVpUdlJREQEDRAdNWoiMesQ1ZtgpNPzFg==
+"@bazel/terser@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-3.4.0.tgz#9a25892977f00974e4195ff6cbe71ec0313a77d5"
+ integrity sha512-E26ijh44aXIXcg3EQEZcL2nkGlWZtMka0gwmYo9bDRyGt6rCRhFuSBC0mz9YCifUhKuACKWXLHPz9wvh1CDkEA==
-"@bazel/typescript@^3.2.0":
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.2.0.tgz#299bd173fe04f98407ab9be4f654662c1c28470e"
- integrity sha512-RKdy9ThbcUAqZR3AJK7AR/nxbJqdHi7pPayIGUSMIpxVkeTxVRQpf1aGe2H02HdZ9fR/uk1xXhO/Ff9TLvTgHQ==
+"@bazel/typescript@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.0.tgz#031d989682ff8605ed8745f31448c2f76a1b653a"
+ integrity sha512-XlWrlQnsdQHTwsliUAf4mySHOgqRY2S57LKG2rKRjm+a015Lzlmxo6jRQaxjr68UmuhmlklRw0WfCFxdR81AvQ==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
source-map-support "0.5.9"
tsutils "2.27.2"
-"@eslint/eslintrc@^0.2.2":
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76"
- integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31"
+ integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
+"@eslint/eslintrc@^0.4.0":
+ version "0.4.0"
+ resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz"
+ integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==
dependencies:
ajv "^6.12.4"
debug "^4.1.1"
@@ -517,7 +541,6 @@
ignore "^4.0.6"
import-fresh "^3.2.1"
js-yaml "^3.13.1"
- lodash "^4.17.19"
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
@@ -529,18 +552,18 @@
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
-"@nodelib/fs.scandir@2.1.3":
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
- integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
+"@nodelib/fs.scandir@2.1.4":
+ version "2.1.4"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz"
+ integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==
dependencies:
- "@nodelib/fs.stat" "2.0.3"
+ "@nodelib/fs.stat" "2.0.4"
run-parallel "^1.1.9"
-"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
- integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
+"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.4"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz"
+ integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==
"@nodelib/fs.stat@^1.1.2":
version "1.1.3"
@@ -548,53 +571,97 @@
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@nodelib/fs.walk@^1.2.3":
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
- integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
+ version "1.2.6"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz"
+ integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==
dependencies:
- "@nodelib/fs.scandir" "2.1.3"
+ "@nodelib/fs.scandir" "2.1.4"
fastq "^1.6.0"
-"@octokit/endpoint@^5.1.0":
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.2.1.tgz#e5ef98bc4a41fad62b17e71af1a1710f6076b8df"
- integrity sha512-GoUsRSRhtbCQugRY8eDWg5BnsczUZNq00qArrP7tKPHFmvz2KzJ8DoEq6IAQhLGwAOBHbZQ/Zml3DiaEKAWwkA==
+"@octokit/auth-token@^2.4.0":
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
+ integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
dependencies:
- deepmerge "4.0.0"
- is-plain-object "^3.0.0"
- universal-user-agent "^2.1.0"
- url-template "^2.0.8"
+ "@octokit/types" "^6.0.3"
-"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.0.4.tgz#15e1dc22123ba4a9a4391914d80ec1e5303a23be"
- integrity sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==
+"@octokit/endpoint@^6.0.1":
+ version "6.0.11"
+ resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1"
+ integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==
dependencies:
+ "@octokit/types" "^6.0.3"
+ is-plain-object "^5.0.0"
+ universal-user-agent "^6.0.0"
+
+"@octokit/openapi-types@^6.0.0":
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-6.0.0.tgz#7da8d7d5a72d3282c1a3ff9f951c8133a707480d"
+ integrity sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ==
+
+"@octokit/plugin-paginate-rest@^1.1.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc"
+ integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==
+ dependencies:
+ "@octokit/types" "^2.0.1"
+
+"@octokit/plugin-request-log@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
+ integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
+
+"@octokit/plugin-rest-endpoint-methods@2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e"
+ integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==
+ dependencies:
+ "@octokit/types" "^2.0.1"
+ deprecation "^2.3.1"
+
+"@octokit/request-error@^1.0.2":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801"
+ integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==
+ dependencies:
+ "@octokit/types" "^2.0.0"
deprecation "^2.0.0"
once "^1.4.0"
-"@octokit/request@^4.0.1":
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/@octokit/request/-/request-4.1.1.tgz#614262214f48417b4d3b14e047d09a9c8e2f7a09"
- integrity sha512-LOyL0i3oxRo418EXRSJNk/3Q4I0/NKawTn6H/CQp+wnrG1UFLGu080gSsgnWobhPo5BpUNgSQ5BRk5FOOJhD1Q==
+"@octokit/request-error@^2.0.0":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143"
+ integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==
dependencies:
- "@octokit/endpoint" "^5.1.0"
- "@octokit/request-error" "^1.0.1"
+ "@octokit/types" "^6.0.3"
deprecation "^2.0.0"
- is-plain-object "^3.0.0"
- node-fetch "^2.3.0"
once "^1.4.0"
- universal-user-agent "^2.1.0"
+
+"@octokit/request@^5.2.0":
+ version "5.4.15"
+ resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.15.tgz#829da413dc7dd3aa5e2cdbb1c7d0ebe1f146a128"
+ integrity sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==
+ dependencies:
+ "@octokit/endpoint" "^6.0.1"
+ "@octokit/request-error" "^2.0.0"
+ "@octokit/types" "^6.7.1"
+ is-plain-object "^5.0.0"
+ node-fetch "^2.6.1"
+ universal-user-agent "^6.0.0"
"@octokit/rest@^16.2.0":
- version "16.28.2"
- resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.28.2.tgz#3fc3b8700046ab29ab1e2a4bdf49f89e94f7ba27"
- integrity sha512-csuYiHvJ1P/GFDadVn0QhwO83R1+YREjcwCY7ZIezB6aJTRIEidJZj+R7gAkUhT687cqYb4cXTZsDVu9F+Fmug==
+ version "16.43.2"
+ resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b"
+ integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==
dependencies:
- "@octokit/request" "^4.0.1"
+ "@octokit/auth-token" "^2.4.0"
+ "@octokit/plugin-paginate-rest" "^1.1.1"
+ "@octokit/plugin-request-log" "^1.0.0"
+ "@octokit/plugin-rest-endpoint-methods" "2.4.0"
+ "@octokit/request" "^5.2.0"
"@octokit/request-error" "^1.0.2"
atob-lite "^2.0.0"
- before-after-hook "^1.4.0"
+ before-after-hook "^2.0.0"
btoa-lite "^1.0.0"
deprecation "^2.0.0"
lodash.get "^4.4.2"
@@ -602,8 +669,21 @@
lodash.uniq "^4.5.0"
octokit-pagination-methods "^1.1.0"
once "^1.4.0"
- universal-user-agent "^2.0.0"
- url-template "^2.0.8"
+ universal-user-agent "^4.0.0"
+
+"@octokit/types@^2.0.0", "@octokit/types@^2.0.1":
+ version "2.16.2"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2"
+ integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==
+ dependencies:
+ "@types/node" ">= 8"
+
+"@octokit/types@^6.0.3", "@octokit/types@^6.7.1":
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.13.0.tgz#779e5b7566c8dde68f2f6273861dd2f0409480d0"
+ integrity sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==
+ dependencies:
+ "@octokit/openapi-types" "^6.0.0"
"@polymer/esm-amd-loader@^1.0.0":
version "1.0.4"
@@ -622,27 +702,27 @@
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
- resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
+ resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
"@protobufjs/base64@^1.1.2":
version "1.1.2"
- resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
+ resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
- resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
+ resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
+ resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
+ resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
dependencies:
"@protobufjs/aspromise" "^1.1.1"
@@ -650,41 +730,53 @@
"@protobufjs/float@^1.0.2":
version "1.0.2"
- resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
+ resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
+ resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
"@protobufjs/path@^1.1.2":
version "1.1.2"
- resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
+ resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
"@protobufjs/pool@^1.1.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
+ resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
- resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
+ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@sindresorhus/is@^0.14.0":
version "0.14.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
+ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
+"@sindresorhus/is@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4"
+ integrity sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==
+
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
+ resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz"
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
dependencies:
defer-to-connect "^1.0.1"
+"@szmarczak/http-timer@^4.0.5":
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
+ integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
+ dependencies:
+ defer-to-connect "^2.0.0"
+
"@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"
@@ -699,7 +791,12 @@
dependencies:
"@types/babel-types" "*"
-"@types/babel-types@*", "@types/babel-types@^6.25.1":
+"@types/babel-types@*":
+ version "7.0.9"
+ resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41"
+ integrity sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA==
+
+"@types/babel-types@^6.25.1":
version "6.25.2"
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e"
integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
@@ -712,29 +809,39 @@
"@types/babel-types" "*"
"@types/bluebird@*":
- version "3.5.29"
- resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
- integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
+ version "3.5.33"
+ resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.33.tgz#d79c020f283bd50bd76101d7d300313c107325fc"
+ integrity sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==
"@types/body-parser@*":
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
- integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
+ integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==
dependencies:
"@types/connect" "*"
"@types/node" "*"
+"@types/cacheable-request@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
+ integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
+ dependencies:
+ "@types/http-cache-semantics" "*"
+ "@types/keyv" "*"
+ "@types/node" "*"
+ "@types/responselike" "*"
+
"@types/chai-subset@^1.3.0":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.2.tgz#16e3267e0557aaec0d77651c0ce27b684f4602c1"
- integrity sha512-VMA1aOXwPEJADlj5ykmYv77YKmbEuAxiLz/+lT6vFIWQ1EA06jF01TytVBAbVTNk0pjfW1Uhw5R5MaEq426N0A==
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
+ integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==
dependencies:
"@types/chai" "*"
"@types/chai@*":
- version "4.1.7"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a"
- integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==
+ version "4.2.16"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.16.tgz#f09cc36e18d28274f942e7201147cce34d97e8c8"
+ integrity sha512-vI5iOAsez9+roLS3M3+Xx7w+WRuDtSmF8bQkrbcIJ2sC1PcDgVoA0WGpa+bIrJ+y8zqY2oi//fUctkxtIcXJCw==
"@types/chalk@^0.4.30":
version "0.4.31"
@@ -749,22 +856,18 @@
chalk "*"
"@types/clean-css@*":
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d"
- integrity sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ==
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.4.tgz#4fe4705c384e6ec9ee8454bc3d49089f38dc038a"
+ integrity sha512-x8xEbfTtcv5uyQDrBXKg9Beo5QhTPqO4vM0uq4iU27/nhyRRWNEMKHjxvAb0WDvp2Mnt4Sw0jKmIi5yQF/k2Ag==
dependencies:
"@types/node" "*"
+ source-map "^0.6.0"
"@types/clone@^0.1.30":
version "0.1.30"
resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
-"@types/color-name@^1.1.1":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
- integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
-
"@types/compression@^0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
@@ -773,9 +876,9 @@
"@types/express" "*"
"@types/connect@*":
- version "3.4.33"
- resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
- integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+ version "3.4.34"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
+ integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
dependencies:
"@types/node" "*"
@@ -806,31 +909,38 @@
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
-"@types/estree@0.0.39":
- version "0.0.39"
- resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
- integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@types/estree@*":
+ version "0.0.47"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
+ integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==
"@types/events@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
-"@types/express-serve-static-core@*":
- version "4.17.1"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.1.tgz#82be64a77211b205641e0209096fd3afb62481d3"
- integrity sha512-9e7jj549ZI+RxY21Cl0t8uBnWyb22HzILupyHZjYEVK//5TT/1bZodU+yUbLnPdoYViBBnNWbxp4zYjGV0zUGw==
+"@types/expect@^1.20.4":
+ version "1.20.4"
+ resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
+ integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
+
+"@types/express-serve-static-core@^4.17.18":
+ version "4.17.19"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
+ integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==
dependencies:
"@types/node" "*"
+ "@types/qs" "*"
"@types/range-parser" "*"
"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
- version "4.17.2"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c"
- integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545"
+ integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==
dependencies:
"@types/body-parser" "*"
- "@types/express-serve-static-core" "*"
+ "@types/express-serve-static-core" "^4.17.18"
+ "@types/qs" "*"
"@types/serve-static" "*"
"@types/fast-levenshtein@0.0.1":
@@ -846,11 +956,11 @@
"@types/minimatch" "*"
"@types/form-data@*":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e"
- integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.5.0.tgz#5025f7433016f923348434c40006d9a797c1b0e8"
+ integrity sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==
dependencies:
- "@types/node" "*"
+ form-data "*"
"@types/freeport@^1.0.19":
version "1.0.21"
@@ -865,12 +975,11 @@
"@types/glob" "*"
"@types/node" "*"
-"@types/glob@*":
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
- integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+"@types/glob@*", "@types/glob@^7.1.1":
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
+ integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
dependencies:
- "@types/events" "*"
"@types/minimatch" "*"
"@types/node" "*"
@@ -898,7 +1007,20 @@
"@types/relateurl" "*"
"@types/uglify-js" "*"
-"@types/inquirer@*", "@types/inquirer@0.0.32":
+"@types/http-cache-semantics@*":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
+ integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
+
+"@types/inquirer@*":
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d"
+ integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==
+ dependencies:
+ "@types/through" "*"
+ rxjs "^6.4.0"
+
+"@types/inquirer@0.0.32":
version "0.0.32"
resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.32.tgz#a4a08e83741c500a7c3c8e7776014f7f8a65870d"
integrity sha1-pKCOg3QcUAp8PI53dgFPf4plhw0=
@@ -912,15 +1034,22 @@
integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
"@types/json-schema@^7.0.3":
- version "7.0.5"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
- integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==
+ version "7.0.7"
+ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz"
+ integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
"@types/json5@^0.0.29":
version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
+"@types/keyv@*":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
+ integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
+ dependencies:
+ "@types/node" "*"
+
"@types/launchpad@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
@@ -928,7 +1057,7 @@
"@types/long@^4.0.0":
version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
+ resolved "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz"
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
"@types/merge-stream@^1.0.28":
@@ -938,19 +1067,24 @@
dependencies:
"@types/node" "*"
-"@types/mime@*", "@types/mime@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
- integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+"@types/mime@^1":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
+ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
-"@types/minimatch@*", "@types/minimatch@^3.0.1":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
- integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+"@types/mime@^2.0.0":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
+ integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==
+
+"@types/minimatch@*", "@types/minimatch@^3.0.1", "@types/minimatch@^3.0.3":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
+ integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
"@types/minimist@^1.2.0":
version "1.2.1"
- resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256"
+ resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz"
integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==
"@types/mz@0.0.29":
@@ -968,24 +1102,24 @@
dependencies:
"@types/node" "*"
-"@types/node@*", "@types/node@^12.0.10":
- version "12.6.1"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.1.tgz#d5544f6de0aae03eefbb63d5120f6c8be0691946"
- integrity sha512-rp7La3m845mSESCgsJePNL/JQyhkOJA6G4vcwvVgkDAwHhGdq5GCumxmPjEk1MZf+8p5ZQAUE7tqgQRQTXN7uQ==
+"@types/node@*", "@types/node@>= 8":
+ version "14.14.37"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
+ integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
"@types/node@^10.1.0":
- version "10.17.49"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.49.tgz#ecf0b67bab4b84d0ec9b0709db4aac3824a51c4a"
- integrity sha512-PGaJNs5IZz5XgzwJvL/1zRfZB7iaJ5BydZ8/Picm+lUNYoNO9iVTQkVy5eUh0dZDrx3rBOIs3GCbCRmMuYyqwg==
+ version "10.17.56"
+ resolved "https://registry.npmjs.org/@types/node/-/node-10.17.56.tgz"
+ integrity sha512-LuAa6t1t0Bfw4CuSR0UITsm1hP17YL+u82kfHGrHUWdhlBtH7sa7jGY5z7glGaIj/WDYDkRtgGd+KCjCzxBW1w==
"@types/node@^4.0.30":
- version "4.9.3"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.3.tgz#a24697a8157ab517996afe0c88fa716550ae419a"
- integrity sha512-Q9eESThBvAbfEzznF1qTAKUoPbJEbK3lTSO0S3mICvmG/vUSZ+HnCtidpuB58Po7CJt5A2goKsDiYScN8d1V4A==
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.5.tgz#a3785db96b07a4b56466cc99fd624838746f2e25"
+ integrity sha512-+8fpgbXsbATKRF2ayAlYhPl2E9MPdLjrnK/79ZEpyPJ+k7dZwJm9YM8FK+l4rqL//xHk7PgQhGwz6aA2ckxbCQ==
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
- resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+ resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
"@types/opn@^3.0.28":
@@ -1014,6 +1148,11 @@
dependencies:
"@types/node" "*"
+"@types/qs@*":
+ version "6.9.6"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
+ integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
+
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
@@ -1053,6 +1192,13 @@
dependencies:
"@types/node" "*"
+"@types/responselike@*", "@types/responselike@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
+ integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
+ dependencies:
+ "@types/node" "*"
+
"@types/rimraf@^0.0.28":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
@@ -1142,9 +1288,9 @@
"@types/rx-core-binding" "*"
"@types/rx@*":
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48"
- integrity sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.2.tgz#a4061b3d72b03cf11a38d69e2022a17334c54dc0"
+ integrity sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==
dependencies:
"@types/rx-core" "*"
"@types/rx-core-binding" "*"
@@ -1165,12 +1311,12 @@
integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
"@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"
- integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==
+ version "1.13.9"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
+ integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
dependencies:
- "@types/express-serve-static-core" "*"
- "@types/mime" "*"
+ "@types/mime" "^1"
+ "@types/node" "*"
"@types/spdy@^3.4.1":
version "3.4.4"
@@ -1187,21 +1333,21 @@
"@types/node" "*"
"@types/through@*":
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93"
- integrity sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==
+ version "0.0.30"
+ resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
+ integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
dependencies:
"@types/node" "*"
"@types/ua-parser-js@^0.7.31":
- version "0.7.33"
- resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz#4a92089511574e12928a7cb6b99a01831acd1dd7"
- integrity sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==
+ version "0.7.35"
+ resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.35.tgz#cca67a95deb9165e4b1f449471801e6489d3fe93"
+ integrity sha512-PsPx0RLbo2Un8+ff2buzYJnZjzwhD3jQHPOG2PtVIeOhkRDddMcKU8vJtHpzzfLB95dkUi0qAkfLg2l2Fd0yrQ==
"@types/uglify-js@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
- integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
+ version "3.13.0"
+ resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.0.tgz#1cad8df1fb0b143c5aba08de5712ea9d1ff71124"
+ integrity sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==
dependencies:
source-map "^0.6.1"
@@ -1211,11 +1357,9 @@
integrity sha512-BLStNhP2DFF7funARwTcoD6tetRte8NK3Sc59mn7GNALCN975jOlKX3dGvsFxXr/HwQMxxCuRn9IWB3WQ7odHQ==
"@types/uuid@^3.4.3":
- version "3.4.5"
- resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.5.tgz#d4dc10785b497a1474eae0ba7f0cb09c0ddfd6eb"
- integrity sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==
- dependencies:
- "@types/node" "*"
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.9.tgz#fcf01997bbc9f7c09ae5f91383af076d466594e1"
+ integrity sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ==
"@types/vinyl-fs@0.0.28":
version "0.0.28"
@@ -1236,10 +1380,11 @@
"@types/vinyl" "*"
"@types/vinyl@*", "@types/vinyl@^2.0.0":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.3.tgz#80a6ce362ab5b32a0c98e860748a31bce9bff0de"
- integrity sha512-hrT6xg16CWSmndZqOTJ6BGIn2abKyTw0B58bI+7ioUoj3Sma6u8ftZ1DTI2yCaJamOVGLOnQWiPH3a74+EaqTA==
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a"
+ integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==
dependencies:
+ "@types/expect" "^1.20.4"
"@types/node" "*"
"@types/whatwg-url@^6.4.0":
@@ -1262,74 +1407,134 @@
"@types/events" "*"
"@types/inquirer" "*"
-"@typescript-eslint/eslint-plugin@^4.11.0", "@typescript-eslint/eslint-plugin@^4.2.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.0.tgz#bc6c1e4175c0cf42083da4314f7931ad12f731cc"
- integrity sha512-x4arJMXBxyD6aBXLm3W7mSDZRiABzy+2PCLJbL7OPqlp53VXhaA1HKK7R2rTee5OlRhnUgnp8lZyVIqjnyPT6g==
+"@typescript-eslint/eslint-plugin@^4.2.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz"
+ integrity sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==
dependencies:
- "@typescript-eslint/experimental-utils" "4.11.0"
- "@typescript-eslint/scope-manager" "4.11.0"
+ "@typescript-eslint/experimental-utils" "4.21.0"
+ "@typescript-eslint/scope-manager" "4.21.0"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
+ lodash "^4.17.15"
regexpp "^3.0.0"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/experimental-utils@4.11.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.0.tgz#d1a47cc6cfe1c080ce4ead79267574b9881a1565"
- integrity sha512-1VC6mSbYwl1FguKt8OgPs8xxaJgtqFpjY/UzUYDBKq4pfQ5lBvN2WVeqYkzf7evW42axUHYl2jm9tNyFsb8oLg==
+"@typescript-eslint/eslint-plugin@^4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz#3d5f29bb59e61a9dba1513d491b059e536e16dbc"
+ integrity sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==
+ dependencies:
+ "@typescript-eslint/experimental-utils" "4.22.0"
+ "@typescript-eslint/scope-manager" "4.22.0"
+ debug "^4.1.1"
+ functional-red-black-tree "^1.0.1"
+ lodash "^4.17.15"
+ regexpp "^3.0.0"
+ semver "^7.3.2"
+ tsutils "^3.17.1"
+
+"@typescript-eslint/experimental-utils@4.21.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz"
+ integrity sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==
dependencies:
"@types/json-schema" "^7.0.3"
- "@typescript-eslint/scope-manager" "4.11.0"
- "@typescript-eslint/types" "4.11.0"
- "@typescript-eslint/typescript-estree" "4.11.0"
+ "@typescript-eslint/scope-manager" "4.21.0"
+ "@typescript-eslint/types" "4.21.0"
+ "@typescript-eslint/typescript-estree" "4.21.0"
+ eslint-scope "^5.0.0"
+ eslint-utils "^2.0.0"
+
+"@typescript-eslint/experimental-utils@4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz#68765167cca531178e7b650a53456e6e0bef3b1f"
+ integrity sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==
+ dependencies:
+ "@types/json-schema" "^7.0.3"
+ "@typescript-eslint/scope-manager" "4.22.0"
+ "@typescript-eslint/types" "4.22.0"
+ "@typescript-eslint/typescript-estree" "4.22.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/parser@^4.2.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.11.0.tgz#1dd3d7e42708c10ce9f3aa64c63c0ab99868b4e2"
- integrity sha512-NBTtKCC7ZtuxEV5CrHUO4Pg2s784pvavc3cnz6V+oJvVbK4tH9135f/RBP6eUA2KHiFKAollSrgSctQGmHbqJQ==
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz"
+ integrity sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==
dependencies:
- "@typescript-eslint/scope-manager" "4.11.0"
- "@typescript-eslint/types" "4.11.0"
- "@typescript-eslint/typescript-estree" "4.11.0"
+ "@typescript-eslint/scope-manager" "4.21.0"
+ "@typescript-eslint/types" "4.21.0"
+ "@typescript-eslint/typescript-estree" "4.21.0"
debug "^4.1.1"
-"@typescript-eslint/scope-manager@4.11.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz#2d906537db8a3a946721699e4fc0833810490254"
- integrity sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==
+"@typescript-eslint/scope-manager@4.21.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz"
+ integrity sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==
dependencies:
- "@typescript-eslint/types" "4.11.0"
- "@typescript-eslint/visitor-keys" "4.11.0"
+ "@typescript-eslint/types" "4.21.0"
+ "@typescript-eslint/visitor-keys" "4.21.0"
-"@typescript-eslint/types@4.11.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.11.0.tgz#86cf95e7eac4ccfd183f9fcf1480cece7caf4ca4"
- integrity sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==
-
-"@typescript-eslint/typescript-estree@4.11.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.0.tgz#1144d145841e5987d61c4c845442a24b24165a4b"
- integrity sha512-eA6sT5dE5RHAFhtcC+b5WDlUIGwnO9b0yrfGa1mIOIAjqwSQCpXbLiFmKTdRbQN/xH2EZkGqqLDrKUuYOZ0+Hg==
+"@typescript-eslint/scope-manager@4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz#ed411545e61161a8d702e703a4b7d96ec065b09a"
+ integrity sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==
dependencies:
- "@typescript-eslint/types" "4.11.0"
- "@typescript-eslint/visitor-keys" "4.11.0"
+ "@typescript-eslint/types" "4.22.0"
+ "@typescript-eslint/visitor-keys" "4.22.0"
+
+"@typescript-eslint/types@4.21.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz"
+ integrity sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==
+
+"@typescript-eslint/types@4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.0.tgz#0ca6fde5b68daf6dba133f30959cc0688c8dd0b6"
+ integrity sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==
+
+"@typescript-eslint/typescript-estree@4.21.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz"
+ integrity sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==
+ dependencies:
+ "@typescript-eslint/types" "4.21.0"
+ "@typescript-eslint/visitor-keys" "4.21.0"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
- lodash "^4.17.15"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/visitor-keys@4.11.0":
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz#906669a50f06aa744378bb84c7d5c4fdbc5b7d51"
- integrity sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==
+"@typescript-eslint/typescript-estree@4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz#b5d95d6d366ff3b72f5168c75775a3e46250d05c"
+ integrity sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==
dependencies:
- "@typescript-eslint/types" "4.11.0"
+ "@typescript-eslint/types" "4.22.0"
+ "@typescript-eslint/visitor-keys" "4.22.0"
+ debug "^4.1.1"
+ globby "^11.0.1"
+ is-glob "^4.0.1"
+ semver "^7.3.2"
+ tsutils "^3.17.1"
+
+"@typescript-eslint/visitor-keys@4.21.0":
+ version "4.21.0"
+ resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz"
+ integrity sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==
+ dependencies:
+ "@typescript-eslint/types" "4.21.0"
+ eslint-visitor-keys "^2.0.0"
+
+"@typescript-eslint/visitor-keys@4.22.0":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz#169dae26d3c122935da7528c839f42a8a42f6e47"
+ integrity sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==
+ dependencies:
+ "@typescript-eslint/types" "4.22.0"
eslint-visitor-keys "^2.0.0"
"@webcomponents/webcomponentsjs@^1.0.7":
@@ -1337,10 +1542,13 @@
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
-abbrev@1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
- integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+JSONStream@^1.2.1, JSONStream@^1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
+ integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
+ dependencies:
+ jsonparse "^1.2.0"
+ through ">=2.2.7 <3"
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
version "1.3.7"
@@ -1364,7 +1572,7 @@
acorn-jsx@^5.3.1:
version "5.3.1"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
+ resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz"
integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
acorn@^3.0.4:
@@ -1373,30 +1581,32 @@
integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
acorn@^5.5.0:
- version "5.7.3"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
- integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+ version "5.7.4"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
+ integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
-acorn@^6.1.1:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3"
- integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==
-
-acorn@^7.4.0:
+acorn@^7.1.0, acorn@^7.4.0:
version "7.4.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
adm-zip@~0.4.3:
- version "0.4.13"
- resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
- integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+ version "0.4.16"
+ resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365"
+ integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
@@ -1404,19 +1614,9 @@
dependencies:
es6-promisify "^5.0.0"
-ajv@^6.10.0:
- version "6.10.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
- integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
- dependencies:
- fast-deep-equal "^2.0.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
- uri-js "^4.2.2"
-
-ajv@^6.12.4:
+ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
@@ -1424,14 +1624,14 @@
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ajv@^6.5.5:
- version "6.10.1"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593"
- integrity sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==
+ajv@^8.0.1:
+ version "8.0.5"
+ resolved "https://registry.npmjs.org/ajv/-/ajv-8.0.5.tgz"
+ integrity sha512-RkiLa/AeJx7+9OvniQ/qeWu0w74A8DiPPBclQ6ji3ZQkv5KamO+QGpqmi7O4JIw3rHGUXZ6CoP9tsAkn3gyazg==
dependencies:
- fast-deep-equal "^2.0.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
uri-js "^4.2.2"
ansi-align@^1.1.0:
@@ -1450,14 +1650,14 @@
ansi-align@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
+ resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz"
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
dependencies:
string-width "^3.0.0"
ansi-colors@^4.1.1:
version "4.1.1"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+ resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-escapes@^1.1.0:
@@ -1465,17 +1665,12 @@
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
-ansi-escapes@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
- integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
-
ansi-escapes@^4.2.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
- integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==
+ version "4.3.2"
+ resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
dependencies:
- type-fest "^0.11.0"
+ type-fest "^0.21.3"
ansi-regex@^2.0.0:
version "2.1.1"
@@ -1489,12 +1684,12 @@
ansi-regex@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz"
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
ansi-styles@^2.2.1:
@@ -1504,26 +1699,18 @@
ansi-styles@^3.2.1:
version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
-ansi-styles@^4.0.0:
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
-ansi-styles@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
- integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
- dependencies:
- "@types/color-name" "^1.1.1"
- color-convert "^2.0.1"
-
ansi-styles@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
@@ -1547,11 +1734,6 @@
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
-aproba@^1.0.3:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
- integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
-
archiver-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
@@ -1581,17 +1763,9 @@
tar-stream "^2.1.0"
zip-stream "^2.1.2"
-are-we-there-yet@~1.1.2:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
- integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^2.0.6"
-
argparse@^1.0.7:
version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
@@ -1635,6 +1809,11 @@
resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+array-differ@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
+ integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
+
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"
@@ -1646,17 +1825,17 @@
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
array-includes@^3.1.1:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8"
- integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz"
+ integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==
dependencies:
- call-bind "^1.0.0"
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.18.0-next.1"
- get-intrinsic "^1.0.1"
+ es-abstract "^1.18.0-next.2"
+ get-intrinsic "^1.1.1"
is-string "^1.0.5"
-array-union@^1.0.1:
+array-union@^1.0.1, array-union@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
@@ -1665,7 +1844,7 @@
array-union@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
array-uniq@^1.0.1:
@@ -1685,7 +1864,7 @@
array.prototype.flat@^1.2.3:
version "1.2.4"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123"
+ resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz"
integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==
dependencies:
call-bind "^1.0.0"
@@ -1699,9 +1878,14 @@
arrify@^1.0.0, arrify@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+ resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+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"
@@ -1721,7 +1905,7 @@
astral-regex@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
+ resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
async-each@^1.0.0:
@@ -1729,24 +1913,22 @@
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+async@0.9.x:
+ version "0.9.2"
+ resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
+ integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
-async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.2, async@^2.6.3:
+async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.0, async@^2.6.2, async@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
dependencies:
lodash "^4.17.14"
-async@^2.6.0, async@^2.6.1:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
- integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
- dependencies:
- lodash "^4.17.11"
+async@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
+ integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
async@~0.2.9:
version "0.2.10"
@@ -1774,9 +1956,16 @@
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
- integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+
+axios@^0.21.1:
+ version "0.21.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+ integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+ dependencies:
+ follow-redirects "^1.10.0"
babel-code-frame@^6.26.0:
version "6.26.0"
@@ -1843,10 +2032,10 @@
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-dynamic-import-node@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
- integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+babel-plugin-dynamic-import-node@^2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
+ integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
dependencies:
object.assign "^4.1.0"
@@ -1862,15 +2051,15 @@
dependencies:
babel-helper-evaluate-path "^0.5.0"
-babel-plugin-minify-dead-code-elimination@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.0.tgz#d23ef5445238ad06e8addf5c1cf6aec835bcda87"
- integrity sha512-XQteBGXlgEoAKc/BhO6oafUdT4LBa7ARi55mxoyhLHNuA+RlzRmeMAfc31pb/UqU01wBzRc36YqHQzopnkd/6Q==
+babel-plugin-minify-dead-code-elimination@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz#1a0c68e44be30de4976ca69ffc535e08be13683f"
+ integrity sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==
dependencies:
babel-helper-evaluate-path "^0.5.0"
babel-helper-mark-eval-scopes "^0.4.3"
babel-helper-remove-or-void "^0.4.3"
- lodash.some "^4.6.0"
+ lodash "^4.17.11"
babel-plugin-minify-flip-comparisons@^0.4.3:
version "0.4.3"
@@ -1879,11 +2068,12 @@
dependencies:
babel-helper-is-void-0 "^0.4.3"
-babel-plugin-minify-guarded-expressions@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.3.tgz#cc709b4453fd21b1f302877444c89f88427ce397"
- integrity sha1-zHCbRFP9IbHzAod0RMifiEJ845c=
+babel-plugin-minify-guarded-expressions@^0.4.3, babel-plugin-minify-guarded-expressions@^0.4.4:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135"
+ integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==
dependencies:
+ babel-helper-evaluate-path "^0.5.0"
babel-helper-flip-expressions "^0.4.3"
babel-plugin-minify-infinity@^0.4.3:
@@ -1908,11 +2098,12 @@
resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c"
integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==
-babel-plugin-minify-simplify@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.0.tgz#1f090018afb90d8b54d3d027fd8a4927f243da6f"
- integrity sha512-TM01J/YcKZ8XIQd1Z3nF2AdWHoDsarjtZ5fWPDksYZNsoOjQ2UO2EWm824Ym6sp127m44gPlLFiO5KFxU8pA5Q==
+babel-plugin-minify-simplify@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a"
+ integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==
dependencies:
+ babel-helper-evaluate-path "^0.5.0"
babel-helper-flip-expressions "^0.4.3"
babel-helper-is-nodes-equiv "^0.0.1"
babel-helper-to-multiple-sequence-expressions "^0.5.0"
@@ -1984,20 +2175,20 @@
integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
babel-preset-minify@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.0.tgz#e25bb8d3590087af02b650967159a77c19bfb96b"
- integrity sha512-xj1s9Mon+RFubH569vrGCayA9Fm2GMsCgDRm1Jb8SgctOB7KFcrVc2o8K3YHUyMz+SWP8aea75BoS8YfsXXuiA==
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f"
+ integrity sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==
dependencies:
babel-plugin-minify-builtins "^0.5.0"
babel-plugin-minify-constant-folding "^0.5.0"
- babel-plugin-minify-dead-code-elimination "^0.5.0"
+ babel-plugin-minify-dead-code-elimination "^0.5.1"
babel-plugin-minify-flip-comparisons "^0.4.3"
- babel-plugin-minify-guarded-expressions "^0.4.3"
+ babel-plugin-minify-guarded-expressions "^0.4.4"
babel-plugin-minify-infinity "^0.4.3"
babel-plugin-minify-mangle-names "^0.5.0"
babel-plugin-minify-numeric-literals "^0.4.3"
babel-plugin-minify-replace "^0.5.0"
- babel-plugin-minify-simplify "^0.5.0"
+ babel-plugin-minify-simplify "^0.5.1"
babel-plugin-minify-type-constructors "^0.4.3"
babel-plugin-transform-inline-consecutive-adds "^0.4.3"
babel-plugin-transform-member-expression-literals "^6.9.4"
@@ -2010,7 +2201,7 @@
babel-plugin-transform-remove-undefined "^0.5.0"
babel-plugin-transform-simplify-comparison-operators "^6.9.4"
babel-plugin-transform-undefined-to-void "^6.9.4"
- lodash.isplainobject "^4.0.6"
+ lodash "^4.17.11"
babel-runtime@^6.22.0, babel-runtime@^6.26.0:
version "6.26.0"
@@ -2061,20 +2252,25 @@
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-arraybuffer@0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
- integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+base64-arraybuffer@0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812"
+ integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=
-base64-js@1.2.0, base64-js@^1.0.2:
+base64-js@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
+base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
base64id@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
@@ -2100,17 +2296,10 @@
dependencies:
tweetnacl "^0.14.3"
-before-after-hook@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.4.0.tgz#2b6bf23dca4f32e628fd2747c10a37c74a4b484d"
- integrity sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg==
-
-better-assert@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
- integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
- dependencies:
- callsite "1.0.0"
+before-after-hook@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.1.tgz#73540563558687586b52ed217dad6a802ab1549c"
+ integrity sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw==
binary-extensions@^1.0.0:
version "1.13.1"
@@ -2118,32 +2307,33 @@
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
binaryextensions@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.2.tgz#c83c3d74233ba7674e4f313cb2a2b70f54e94b7c"
- integrity sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22"
+ integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==
+
+bindings@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+ integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+ dependencies:
+ file-uri-to-path "1.0.0"
bl@^1.0.0:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
- integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
+ integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==
dependencies:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
-bl@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
- integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+bl@^4.0.3:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
- readable-stream "^2.3.5"
- safe-buffer "^5.1.1"
-
-bl@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
- integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
- dependencies:
- readable-stream "^3.0.1"
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
blob@0.0.5:
version "0.0.5"
@@ -2167,25 +2357,28 @@
type-is "~1.6.17"
bower-config@^1.4.0, bower-config@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc"
- integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw=
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.3.tgz#3454fecdc5f08e7aa9cc6d556e492be0669689ae"
+ integrity sha512-MVyyUk3d1S7d2cl6YISViwJBc2VXCkxF5AUFykvN0PQj5FsUiMNSgAYTso18oRFfyZ6XEtjrgg9MAaufHbOwNw==
dependencies:
graceful-fs "^4.1.3"
+ minimist "^0.2.1"
mout "^1.0.0"
- optimist "^0.6.1"
osenv "^0.1.3"
untildify "^2.1.0"
+ wordwrap "^0.0.3"
bower-json@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.1.tgz#96c14723241ae6466a9c52e16caa32623a883843"
- integrity sha1-lsFHIyQa5kZqnFLhbKoyYjqIOEM=
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.4.tgz#9c3b375870dcd9581350c1f403f6383dbf6a18b1"
+ integrity sha512-mMKghvq9ivbuzSsY5nrOLnDtZIJMUCpysqbGaGW3mj88JAcuSi8ZAzIt34vNZjohy0aR9VXLwgPTZGnBX2Vpjg==
dependencies:
- deep-extend "^0.4.0"
- ext-name "^3.0.0"
+ deep-extend "^0.5.1"
+ ends-with "^0.2.0"
+ ext-list "^2.0.0"
graceful-fs "^4.1.3"
intersect "^1.0.1"
+ sort-keys-length "^1.0.0"
bower-logger@^0.2.2:
version "0.2.2"
@@ -2193,9 +2386,9 @@
integrity sha1-Ob4H6Xmy/I4DqUY0IF7ZQiNz04E=
bower@^1.8.8:
- version "1.8.8"
- resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.8.tgz#82544be34a33aeae7efb8bdf9905247b2cffa985"
- integrity sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==
+ version "1.8.12"
+ resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.12.tgz#44cfca2a5e04b8d9a066621e24c8b179d8ac321e"
+ integrity sha512-u1xy9SrwwoPlgjuHNjhV+YUPVdqyBj2ALBxuzeIUKXaPI2i2xypGgxqXkuHcITGdi5yBj5JuXgyMvgiWiS1S3Q==
boxen@^0.6.0:
version "0.6.0"
@@ -2225,23 +2418,23 @@
term-size "^1.2.0"
widest-line "^2.0.0"
-boxen@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
- integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
+boxen@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/boxen/-/boxen-5.0.1.tgz"
+ integrity sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==
dependencies:
ansi-align "^3.0.0"
- camelcase "^5.3.1"
- chalk "^3.0.0"
- cli-boxes "^2.2.0"
- string-width "^4.1.0"
- term-size "^2.1.0"
- type-fest "^0.8.1"
+ camelcase "^6.2.0"
+ chalk "^4.1.0"
+ cli-boxes "^2.2.1"
+ string-width "^4.2.0"
+ type-fest "^0.20.2"
widest-line "^3.1.0"
+ wrap-ansi "^7.0.0"
brace-expansion@^1.1.7:
version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
@@ -2274,7 +2467,7 @@
braces@^3.0.1:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
@@ -2294,10 +2487,21 @@
dependencies:
pako "~0.2.0"
+browserslist@^4.14.5:
+ version "4.16.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
+ integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
+ dependencies:
+ caniuse-lite "^1.0.30001181"
+ colorette "^1.2.1"
+ electron-to-chromium "^1.3.649"
+ escalade "^3.1.1"
+ node-releases "^1.1.70"
+
browserstack@^1.2.0:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
- integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3"
+ integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==
dependencies:
https-proxy-agent "^2.2.1"
@@ -2331,16 +2535,16 @@
buffer-from@^1.0.0:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+ resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-buffer@^5.1.0:
- version "5.4.3"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
- integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
+buffer@^5.1.0, buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
- base64-js "^1.0.2"
- ieee754 "^1.1.4"
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
busboy@^0.2.11:
version "0.2.14"
@@ -2375,9 +2579,14 @@
union-value "^1.0.0"
unset-value "^1.0.0"
+cacheable-lookup@^5.0.3:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
+ integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+
cacheable-request@^6.0.0:
version "6.1.0"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
+ resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz"
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
dependencies:
clone-response "^1.0.2"
@@ -2388,27 +2597,35 @@
normalize-url "^4.1.0"
responselike "^1.0.2"
-call-bind@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce"
- integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
+cacheable-request@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
+ integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
+ dependencies:
+ clone-response "^1.0.2"
+ get-stream "^5.1.0"
+ http-cache-semantics "^4.0.0"
+ keyv "^4.0.0"
+ lowercase-keys "^2.0.0"
+ normalize-url "^4.1.0"
+ responselike "^2.0.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
dependencies:
function-bind "^1.1.1"
- get-intrinsic "^1.0.0"
+ get-intrinsic "^1.0.2"
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-callsite@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
- integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
-
callsites@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
camel-case@3.0.x:
@@ -2429,7 +2646,7 @@
camelcase-keys@^6.2.2:
version "6.2.2"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
+ resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz"
integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
dependencies:
camelcase "^5.3.1"
@@ -2448,9 +2665,14 @@
camelcase@^5.3.1:
version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+camelcase@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz"
+ integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
+
cancel-token@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/cancel-token/-/cancel-token-0.1.1.tgz#c18197674bb1c84c1d6933ebf15d8d5a5ce79b4f"
@@ -2458,6 +2680,11 @@
dependencies:
"@types/node" "^4.0.30"
+caniuse-lite@^1.0.30001181:
+ version "1.0.30001208"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz#a999014a35cebd4f98c405930a057a0d75352eb9"
+ integrity sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==
+
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"
@@ -2468,14 +2695,13 @@
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-chalk@*, chalk@^2.0.0, chalk@^2.0.1, 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==
+chalk@*, chalk@^4.0.0, chalk@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz"
+ integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
@@ -2488,21 +2714,14 @@
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^4.0.0, chalk@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
- integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
chalk@~0.4.0:
version "0.4.0"
@@ -2515,10 +2734,10 @@
chardet@^0.7.0:
version "0.7.0"
- resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-charenc@~0.0.1:
+charenc@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
@@ -2540,14 +2759,9 @@
fsevents "^1.0.0"
chownr@^1.0.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
- integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==
-
-chownr@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
- integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
ci-info@^1.5.0:
version "1.6.0"
@@ -2556,7 +2770,7 @@
ci-info@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
+ resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
class-utils@^0.3.5:
@@ -2570,9 +2784,9 @@
static-extend "^0.1.1"
clean-css@4.2.x:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
- integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+ 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"
@@ -2586,9 +2800,9 @@
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
-cli-boxes@^2.2.0:
+cli-boxes@^2.2.1:
version "2.2.1"
- resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
+ resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz"
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
cli-cursor@^1.0.1:
@@ -2598,35 +2812,28 @@
dependencies:
restore-cursor "^1.0.1"
-cli-cursor@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
- integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
- dependencies:
- restore-cursor "^2.0.0"
-
cli-cursor@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz"
integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
dependencies:
restore-cursor "^3.1.0"
cli-table@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
- integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.6.tgz#e9d6aa859c7fe636981fd3787378c2a20bce92fc"
+ integrity sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==
dependencies:
colors "1.0.3"
cli-width@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
- integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
+ integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
cli-width@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clone-buffer@^1.0.0:
@@ -2634,9 +2841,18 @@
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+clone-deep@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+ integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
+ dependencies:
+ is-plain-object "^2.0.4"
+ kind-of "^6.0.2"
+ shallow-clone "^3.0.0"
+
clone-response@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
+ resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
@@ -2685,32 +2901,32 @@
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-convert@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
-color-name@1.1.3, color-name@^1.0.0:
+color-name@1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-color-name@~1.1.4:
+color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.5.2:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
- integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014"
+ integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
@@ -2723,10 +2939,10 @@
color-convert "^1.9.1"
color-string "^1.5.2"
-colornames@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
- integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
+colorette@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+ integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colors@1.0.3:
version "1.0.3"
@@ -2734,9 +2950,9 @@
integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
colors@^1.2.1:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
- integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
+ integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
colorspace@1.1.x:
version "1.1.2"
@@ -2746,7 +2962,7 @@
color "3.0.x"
text-hex "1.0.x"
-combined-stream@^1.0.6, combined-stream@~1.0.6:
+combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@@ -2785,7 +3001,7 @@
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
-commander@^2.19.0, commander@^2.20.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==
@@ -2795,10 +3011,10 @@
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
-comment-parser@^0.7.6:
- version "0.7.6"
- resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.7.6.tgz#0e743a53c8e646c899a1323db31f6cd337b10f12"
- integrity sha512-GKNxVA7/iuTnAqGADlTWX4tkhzxZKXp5fLJqKTlQLHkE65XDUKutZ3BHaJC5IGcper2tT3QRD1xr4o3jNpgXXg==
+comment-parser@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.1.2.tgz#e5317d7a2ec22b470dcb54a29b25426c30bf39d8"
+ integrity sha512-AOdq0i8ghZudnYv8RUnHrhTgafUGs61Rdz9jemU5x2lnZwAWyOq7vySo626K59e1fVKH1xSRorJwPVRLSWOoAQ==
commondir@^1.0.1:
version "1.0.1"
@@ -2815,7 +3031,7 @@
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
-component-emitter@^1.2.1:
+component-emitter@^1.2.1, component-emitter@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
@@ -2857,7 +3073,7 @@
concat-map@0.0.1:
version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.4.7, concat-stream@^1.5.2:
@@ -2886,11 +3102,11 @@
xdg-basedir "^2.0.0"
configstore@^3.0.0:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
- integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.5.tgz#e9af331fadc14dabd544d3e7e76dc446a09a530f"
+ integrity sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==
dependencies:
- dot-prop "^4.1.0"
+ dot-prop "^4.2.1"
graceful-fs "^4.1.2"
make-dir "^1.0.0"
unique-string "^1.0.0"
@@ -2899,7 +3115,7 @@
configstore@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
+ resolved "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz"
integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
dependencies:
dot-prop "^5.2.0"
@@ -2909,14 +3125,9 @@
write-file-atomic "^3.0.0"
xdg-basedir "^4.0.0"
-console-control-strings@^1.0.0, console-control-strings@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
- integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
-
contains-path@^0.1.0:
version "0.1.0"
- resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
+ resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz"
integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
content-disposition@0.5.3:
@@ -2931,10 +3142,10 @@
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-convert-source-map@^1.1.0, convert-source-map@^1.1.1:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
- integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
+convert-source-map@^1.1.1, convert-source-map@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+ integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
dependencies:
safe-buffer "~5.1.1"
@@ -2943,25 +3154,25 @@
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-cookie@0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
- integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
-
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookie@~0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
+ integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
+
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@^2.4.0:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
- integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+ integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
@@ -3018,16 +3229,16 @@
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
-crypt@~0.0.1:
+crypt@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
@@ -3039,7 +3250,7 @@
crypto-random-string@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
+ resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
css-slam@^2.1.2:
@@ -3070,7 +3281,7 @@
dependencies:
array-find-index "^1.0.1"
-dargs@^6.0.0:
+dargs@^6.0.0, dargs@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/dargs/-/dargs-6.1.0.tgz#1f3b9b56393ecf8caa7cbfd6c31496ffcfb9b272"
integrity sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==
@@ -3089,32 +3300,25 @@
debug@2.6.9, debug@^2.0.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
-debug@^3.0.0, debug@^3.1.0:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
- integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.3.1:
+debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
version "4.3.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
+ resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
+debug@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -3122,17 +3326,24 @@
dependencies:
ms "2.0.0"
+debug@~4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+ integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+ dependencies:
+ ms "^2.1.1"
+
decamelize-keys@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
+ resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz"
integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
dependencies:
decamelize "^1.1.0"
map-obj "^1.0.0"
-decamelize@^1.1.0, decamelize@^1.1.2:
+decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
decode-uri-component@^0.2.0:
@@ -3142,39 +3353,46 @@
decompress-response@^3.2.0, decompress-response@^3.3.0:
version "3.3.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
+ resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz"
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
dependencies:
mimic-response "^1.0.0"
-deep-extend@^0.4.0:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
- integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
+decompress-response@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+ integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+ dependencies:
+ mimic-response "^3.1.0"
+
+deep-extend@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f"
+ integrity sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==
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"
+ resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
deep-is@^0.1.3:
version "0.1.3"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+ resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
-deepmerge@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09"
- integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww==
-
defer-to-connect@^1.0.1:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
+ resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-define-properties@^1.1.2, define-properties@^1.1.3:
+defer-to-connect@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
+ integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
+
+define-properties@^1.1.3:
version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
dependencies:
object-keys "^1.0.12"
@@ -3218,17 +3436,12 @@
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-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:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-deprecation@^2.0.0:
+deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
@@ -3262,24 +3475,10 @@
dependencies:
repeating "^2.0.0"
-detect-libc@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
- integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
-
detect-node@^2.0.3:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
- integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
-
-diagnostics@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
- integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==
- dependencies:
- colorspace "1.1.x"
- enabled "1.0.x"
- kuler "1.0.x"
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79"
+ integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==
dicer@0.2.5:
version "0.2.5"
@@ -3299,6 +3498,11 @@
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
dir-glob@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
@@ -3307,16 +3511,23 @@
arrify "^1.0.1"
path-type "^3.0.0"
+dir-glob@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
+ integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==
+ dependencies:
+ path-type "^3.0.0"
+
dir-glob@^3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
path-type "^4.0.0"
doctrine@1.5.0:
version "1.5.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz"
integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
dependencies:
esutils "^2.0.2"
@@ -3331,15 +3542,15 @@
doctrine@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
dom-serializer@^1.0.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
- integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz"
+ integrity sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
@@ -3361,33 +3572,26 @@
clone "^2.1.0"
parse5 "^4.0.0"
-domelementtype@^2.0.1, domelementtype@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e"
- integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz"
+ integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
-domhandler@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a"
- integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==
+domhandler@^4.0.0, domhandler@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz"
+ integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
dependencies:
- domelementtype "^2.0.1"
+ domelementtype "^2.2.0"
-domhandler@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e"
- integrity sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==
- dependencies:
- domelementtype "^2.1.0"
-
-domutils@^2.4.2:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.4.4.tgz#282739c4b150d022d34699797369aad8d19bbbd3"
- integrity sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==
+domutils@^2.5.2:
+ version "2.5.2"
+ resolved "https://registry.npmjs.org/domutils/-/domutils-2.5.2.tgz"
+ integrity sha512-MHTthCb1zj8f1GVfRpeZUbohQf/HdBos0oX5gZcQFepOZPLLRyj6Wn7XS7EMnY7CVpwv8863u2vyE83Hfu28HQ==
dependencies:
dom-serializer "^1.0.1"
- domelementtype "^2.0.1"
- domhandler "^4.0.0"
+ domelementtype "^2.2.0"
+ domhandler "^4.1.0"
dot-prop@^3.0.0:
version "3.0.0"
@@ -3396,20 +3600,29 @@
dependencies:
is-obj "^1.0.0"
-dot-prop@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
- integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
+dot-prop@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4"
+ integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==
dependencies:
is-obj "^1.0.0"
dot-prop@^5.2.0:
version "5.3.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
+ resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz"
integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
dependencies:
is-obj "^2.0.0"
+download-stats@^0.3.4:
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/download-stats/-/download-stats-0.3.4.tgz#67ea0c32f14acd9f639da704eef509684ba2dae7"
+ integrity sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==
+ dependencies:
+ JSONStream "^1.2.1"
+ lazy-cache "^2.0.1"
+ moment "^2.15.1"
+
duplexer2@^0.1.2, duplexer2@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -3419,7 +3632,7 @@
duplexer3@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
+ resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
@@ -3440,23 +3653,35 @@
jsbn "~0.1.0"
safer-buffer "^2.1.0"
-editions@^2.1.2, editions@^2.1.3:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/editions/-/editions-2.1.3.tgz#727ccf3ec2c7b12dcc652c71000f16c4824d6f7d"
- integrity sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw==
+editions@^2.2.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698"
+ integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==
dependencies:
- errlop "^1.1.1"
- semver "^5.6.0"
+ errlop "^2.0.0"
+ semver "^6.3.0"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-ejs@^2.5.9:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6"
- integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q==
+ejs@^2.5.9, ejs@^2.6.1:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
+ integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
+
+ejs@^3.1.5:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a"
+ integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==
+ dependencies:
+ jake "^10.6.1"
+
+electron-to-chromium@^1.3.649:
+ version "1.3.712"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.712.tgz#ae467ffe5f95961c6d41ceefe858fc36eb53b38f"
+ integrity sha512-3kRVibBeCM4vsgoHHGKHmPocLqtFAGTrebXxxtgKs87hNUzXrX2NuS3jnBys7IozCnw7viQlozxKkmty2KNfrw==
emitter-component@^1.1.1:
version "1.1.1"
@@ -3465,36 +3690,27 @@
emoji-regex@^7.0.1:
version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0:
version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-enabled@1.0.x:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
- integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=
- dependencies:
- env-variable "0.0.x"
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
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.1.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
- integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
- dependencies:
- once "^1.4.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"
+ resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
@@ -3504,106 +3720,102 @@
resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a"
integrity sha1-L52pjVelDP2kVxzkM5AAUA9Oa4o=
-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"
- integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
+engine.io-client@~3.5.0:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.5.1.tgz#b500458a39c0cd197a921e0e759721a746d0bdb9"
+ integrity sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==
dependencies:
- component-emitter "1.2.1"
+ component-emitter "~1.3.0"
component-inherit "0.0.3"
- debug "~4.1.0"
+ debug "~3.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
- parseqs "0.0.5"
- parseuri "0.0.5"
- ws "~6.1.0"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
+ ws "~7.4.2"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.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"
- integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
+ integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
- base64-arraybuffer "0.1.5"
+ base64-arraybuffer "0.1.4"
blob "0.0.5"
has-binary2 "~1.0.2"
-engine.io@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
- integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
+engine.io@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
+ integrity sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==
dependencies:
accepts "~1.3.4"
base64id "2.0.0"
- cookie "0.3.1"
+ cookie "~0.4.1"
debug "~4.1.0"
engine.io-parser "~2.2.0"
- ws "^7.1.2"
+ ws "~7.4.2"
enquirer@^2.3.5:
version "2.3.6"
- resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
+ resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
dependencies:
ansi-colors "^4.1.1"
entities@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
- integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
-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==
-
-errlop@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.1.tgz#d9ae4c76c3e64956c5d79e6e035d6343bfd62250"
- integrity sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw==
- dependencies:
- editions "^2.1.2"
+errlop@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b"
+ integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==
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"
+ resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
error@^7.0.2:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02"
- integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894"
+ integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==
dependencies:
string-template "~0.2.1"
- xtend "~4.0.0"
-es-abstract@^1.18.0-next.1:
- version "1.18.0-next.1"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
- integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
+es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2:
+ version "1.18.0"
+ resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz"
+ integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==
dependencies:
+ call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
+ get-intrinsic "^1.1.1"
has "^1.0.3"
- has-symbols "^1.0.1"
- is-callable "^1.2.2"
- is-negative-zero "^2.0.0"
- is-regex "^1.1.1"
- object-inspect "^1.8.0"
+ has-symbols "^1.0.2"
+ is-callable "^1.2.3"
+ is-negative-zero "^2.0.1"
+ is-regex "^1.1.2"
+ is-string "^1.0.5"
+ object-inspect "^1.9.0"
object-keys "^1.1.1"
- object.assign "^4.1.1"
- string.prototype.trimend "^1.0.1"
- string.prototype.trimstart "^1.0.1"
+ object.assign "^4.1.2"
+ string.prototype.trimend "^1.0.4"
+ string.prototype.trimstart "^1.0.4"
+ unbox-primitive "^1.0.0"
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"
+ resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
dependencies:
is-callable "^1.1.4"
@@ -3623,13 +3835,18 @@
es6-promise "^4.0.3"
es6-promisify@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4"
- integrity sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
+ integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-goat@^2.0.0:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
+ resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
escape-html@^1.0.3, escape-html@~1.0.3:
@@ -3639,24 +3856,22 @@
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
eslint-config-google@^0.14.0:
version "0.14.0"
- resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a"
+ resolved "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz"
integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==
-eslint-config-prettier@^6.12.0:
- version "6.15.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9"
- integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==
- dependencies:
- get-stdin "^6.0.0"
+eslint-config-prettier@^7.0.0:
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz"
+ integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==
eslint-import-resolver-node@^0.3.4:
version "0.3.4"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
+ resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
dependencies:
debug "^2.6.9"
@@ -3664,7 +3879,7 @@
eslint-module-utils@^2.6.0:
version "2.6.0"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6"
+ resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz"
integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==
dependencies:
debug "^2.6.9"
@@ -3672,22 +3887,22 @@
eslint-plugin-es@^3.0.0:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
+ resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz"
integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
dependencies:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
-eslint-plugin-html@^6.1.1:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.1.1.tgz#95aee151900b9bb2da5fa017b45cc64456a0a74e"
- integrity sha512-JSe3ZDb7feKMnQM27XWGeoIjvP4oWQMJD9GZ6wW67J7/plVL87NK72RBwlvfc3tTZiYUchHhxAwtgEd1GdofDA==
+eslint-plugin-html@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.1.2.tgz#fa26e4804428956c80e963b6499c192061c2daf3"
+ integrity sha512-bhBIRyZFqI4EoF12lGDHAmgfff8eLXx6R52/K3ESQhsxzCzIE6hdebS7Py651f7U3RBotqroUnC3L29bR7qJWQ==
dependencies:
- htmlparser2 "^5.0.1"
+ htmlparser2 "^6.0.1"
eslint-plugin-import@^2.22.1:
version "2.22.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702"
+ resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz"
integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==
dependencies:
array-includes "^3.1.1"
@@ -3704,12 +3919,12 @@
resolve "^1.17.0"
tsconfig-paths "^3.9.0"
-eslint-plugin-jsdoc@^30.7.9:
- version "30.7.9"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.9.tgz#b0a9881990edc1bc8a635467bad9edfae9ecbaaf"
- integrity sha512-qMM0fNx7/6OCnIh3jRpIrEBAhTG1THNXXbr3yfJ8yqLrDbzJR98xsstX25xt9GCPlrjNc/bBpTHfJQOvn7nVMA==
+eslint-plugin-jsdoc@^32.3.0:
+ version "32.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.0.tgz#7c9fa5da8c72bd6ad7d97bbf8dee8bc29bec3f9e"
+ integrity sha512-zyx7kajDK+tqS1bHuY5sapkad8P8KT0vdd/lE55j47VPG2MeenSYuIY/M/Pvmzq5g0+3JB+P3BJGUXmHxtuKPQ==
dependencies:
- comment-parser "^0.7.6"
+ comment-parser "1.1.2"
debug "^4.3.1"
jsdoctypeparser "^9.0.0"
lodash "^4.17.20"
@@ -3719,7 +3934,7 @@
eslint-plugin-node@^11.1.0:
version "11.1.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
+ resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz"
integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
dependencies:
eslint-plugin-es "^3.0.0"
@@ -3729,24 +3944,23 @@
resolve "^1.10.1"
semver "^6.1.0"
-eslint-plugin-prettier@^3.1.4, eslint-plugin-prettier@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz#61e295349a65688ffac0b7808ef0a8244bdd8d40"
- integrity sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==
+eslint-plugin-prettier@^3.1.4:
+ version "3.3.1"
+ resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz"
+ integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==
dependencies:
prettier-linter-helpers "^1.0.0"
-eslint-scope@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
- integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
+eslint-plugin-prettier@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7"
+ integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==
dependencies:
- esrecurse "^4.1.0"
- estraverse "^4.1.1"
+ prettier-linter-helpers "^1.0.0"
-eslint-scope@^5.1.1:
+eslint-scope@^5.0.0, eslint-scope@^5.1.1:
version "5.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
esrecurse "^4.3.0"
@@ -3754,33 +3968,28 @@
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+ resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
-eslint-visitor-keys@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
- integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
-
-eslint-visitor-keys@^1.3.0:
+eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+ resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-visitor-keys@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
+ resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint@^7.10.0, eslint@^7.16.0:
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092"
- integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==
+eslint@^7.10.0:
+ version "7.23.0"
+ resolved "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz"
+ integrity sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==
dependencies:
- "@babel/code-frame" "^7.0.0"
- "@eslint/eslintrc" "^0.2.2"
+ "@babel/code-frame" "7.12.11"
+ "@eslint/eslintrc" "^0.4.0"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
@@ -3791,12 +4000,12 @@
eslint-utils "^2.1.0"
eslint-visitor-keys "^2.0.0"
espree "^7.3.1"
- esquery "^1.2.0"
+ esquery "^1.4.0"
esutils "^2.0.2"
- file-entry-cache "^6.0.0"
+ file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
- globals "^12.1.0"
+ globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
@@ -3804,7 +4013,50 @@
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
- lodash "^4.17.19"
+ lodash "^4.17.21"
+ minimatch "^3.0.4"
+ natural-compare "^1.4.0"
+ optionator "^0.9.1"
+ progress "^2.0.0"
+ regexpp "^3.1.0"
+ semver "^7.2.1"
+ strip-ansi "^6.0.0"
+ strip-json-comments "^3.1.0"
+ table "^6.0.4"
+ text-table "^0.2.0"
+ v8-compile-cache "^2.0.3"
+
+eslint@^7.24.0:
+ version "7.24.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a"
+ integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==
+ dependencies:
+ "@babel/code-frame" "7.12.11"
+ "@eslint/eslintrc" "^0.4.0"
+ ajv "^6.10.0"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ enquirer "^2.3.5"
+ eslint-scope "^5.1.1"
+ eslint-utils "^2.1.0"
+ eslint-visitor-keys "^2.0.0"
+ espree "^7.3.1"
+ esquery "^1.4.0"
+ esutils "^2.0.2"
+ file-entry-cache "^6.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob-parent "^5.0.0"
+ globals "^13.6.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ js-yaml "^3.13.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash "^4.17.21"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
@@ -3827,7 +4079,7 @@
espree@^7.3.0, espree@^7.3.1:
version "7.3.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
+ resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz"
integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
dependencies:
acorn "^7.4.0"
@@ -3836,44 +4088,37 @@
esprima@^4.0.0:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-esquery@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
- integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
+esquery@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz"
+ integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
dependencies:
estraverse "^5.1.0"
-esrecurse@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
- integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
- dependencies:
- estraverse "^4.1.0"
-
esrecurse@^4.3.0:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
-estraverse@^4.1.0, estraverse@^4.1.1:
+estraverse@^4.1.1:
version "4.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.1.0, estraverse@^5.2.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
+ resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
esutils@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
- integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
etag@~1.8.1:
version "1.8.1"
@@ -3881,9 +4126,9 @@
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
- integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
execa@^0.7.0:
version "0.7.0"
@@ -3911,9 +4156,24 @@
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
+ integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
+ dependencies:
+ cross-spawn "^7.0.0"
+ get-stream "^5.0.0"
+ human-signals "^1.1.1"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.0"
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+ strip-final-newline "^2.0.0"
+
execa@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376"
+ resolved "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz"
integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==
dependencies:
cross-spawn "^7.0.3"
@@ -4015,16 +4275,6 @@
dependencies:
mime-db "^1.28.0"
-ext-name@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-3.0.0.tgz#07e4418737cb1f513c32c6ea48d8b8c8e0471abb"
- integrity sha1-B+RBhzfLH1E8MsbqSNi4yOBHGrs=
- dependencies:
- ends-with "^0.2.0"
- ext-list "^2.0.0"
- meow "^3.1.0"
- sort-keys-length "^1.0.0"
-
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -4056,7 +4306,7 @@
external-editor@^3.0.3:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz"
integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
dependencies:
chardet "^0.7.0"
@@ -4084,27 +4334,27 @@
snapdragon "^0.8.1"
to-regex "^3.0.1"
-extsprintf@1.3.0, extsprintf@^1.2.0:
+extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
-fast-deep-equal@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
- integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+extsprintf@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+ integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1:
version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
+ resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
-fast-glob@^2.0.2:
+fast-glob@^2.0.2, fast-glob@^2.2.6:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
@@ -4117,9 +4367,9 @@
micromatch "^3.1.10"
fast-glob@^3.1.1:
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
- integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==
+ version "3.2.5"
+ resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz"
+ integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
@@ -4129,24 +4379,24 @@
picomatch "^2.2.1"
fast-json-stable-stringify@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
- integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6:
version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fast-safe-stringify@^2.0.4:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
- integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
+ integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
fastq@^1.6.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.10.0.tgz#74dbefccade964932cdf500473ef302719c652bb"
- integrity sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==
+ version "1.11.0"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz"
+ integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
dependencies:
reusify "^1.0.4"
@@ -4162,6 +4412,11 @@
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+fecha@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce"
+ integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==
+
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -4170,27 +4425,32 @@
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
-figures@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
- integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
- dependencies:
- escape-string-regexp "^1.0.5"
-
figures@^3.0.0:
version "3.2.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
dependencies:
escape-string-regexp "^1.0.5"
-file-entry-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a"
- integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
dependencies:
flat-cache "^3.0.4"
+file-uri-to-path@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+ integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
+filelist@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b"
+ integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==
+ dependencies:
+ minimatch "^3.0.4"
+
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -4219,7 +4479,7 @@
fill-range@^7.0.1:
version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
@@ -4266,7 +4526,7 @@
find-up@^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"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz"
integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
dependencies:
locate-path "^2.0.0"
@@ -4280,7 +4540,7 @@
find-up@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
@@ -4320,23 +4580,26 @@
flat-cache@^3.0.4:
version "3.0.4"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
+ resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz"
integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
dependencies:
flatted "^3.1.0"
rimraf "^3.0.2"
flatted@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067"
- integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz"
+ integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
-follow-redirects@^1.0.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
- integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
- dependencies:
- debug "^3.0.0"
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
+
+follow-redirects@^1.0.0, follow-redirects@^1.10.0:
+ version "1.13.3"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
+ integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
@@ -4360,6 +4623,15 @@
resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
+form-data@*:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@@ -4408,59 +4680,43 @@
resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
-fs-minipass@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
- integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==
- dependencies:
- minipass "^2.2.1"
-
fs.realpath@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@^1.0.0:
- version "1.2.9"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
- integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
+ integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
dependencies:
+ bindings "^1.5.0"
nan "^2.12.1"
- node-pre-gyp "^0.12.0"
-fsevents@~2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
- integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
+fsevents@~2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
functional-red-black-tree@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+ resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-gauge@~2.7.3:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
- integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
- dependencies:
- aproba "^1.0.3"
- console-control-strings "^1.0.0"
- has-unicode "^2.0.0"
- object-assign "^4.1.0"
- signal-exit "^3.0.0"
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wide-align "^1.1.0"
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-get-intrinsic@^1.0.0, get-intrinsic@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
- integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz"
+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
@@ -4471,11 +4727,6 @@
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
-get-stdin@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
- integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
-
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -4483,21 +4734,21 @@
get-stream@^4.0.0, get-stream@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
-get-stream@^5.1.0:
+get-stream@^5.0.0, get-stream@^5.1.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
get-stream@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz"
integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==
get-value@^2.0.3, get-value@^2.0.6:
@@ -4512,6 +4763,14 @@
dependencies:
assert-plus "^1.0.0"
+gh-got@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-5.0.0.tgz#ee95be37106fd8748a96f8d1db4baea89e1bfa8a"
+ integrity sha1-7pW+NxBv2HSKlvjR20uuqJ4b+oo=
+ dependencies:
+ got "^6.2.0"
+ is-plain-obj "^1.1.0"
+
gh-got@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0"
@@ -4520,6 +4779,13 @@
got "^7.0.0"
is-plain-obj "^1.1.0"
+github-username@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/github-username/-/github-username-3.0.0.tgz#0a772219b3130743429f2456d0bdd3db55dce7b1"
+ integrity sha1-CnciGbMTB0NCnyRW0L3T21Xc57E=
+ dependencies:
+ gh-got "^5.0.0"
+
github-username@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417"
@@ -4550,17 +4816,10 @@
is-glob "^3.1.0"
path-dirname "^1.0.0"
-glob-parent@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
- integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
- dependencies:
- is-glob "^4.0.1"
-
-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==
+glob-parent@^5.0.0, glob-parent@^5.1.0:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
@@ -4605,21 +4864,9 @@
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2:
- version "7.1.4"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
- integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.1.3, glob@^7.1.4:
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
@@ -4636,12 +4883,12 @@
dependencies:
ini "^1.3.4"
-global-dirs@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d"
- integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==
+global-dirs@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz"
+ integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==
dependencies:
- ini "1.3.7"
+ ini "2.0.0"
global-modules@^0.2.3:
version "0.2.3"
@@ -4687,21 +4934,28 @@
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^12.1.0:
- version "12.3.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
- integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==
+ version "12.4.0"
+ resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz"
+ integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
dependencies:
type-fest "^0.8.1"
+globals@^13.6.0:
+ version "13.8.0"
+ resolved "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz"
+ integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==
+ dependencies:
+ type-fest "^0.20.2"
+
globals@^9.18.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
globby@^11.0.1:
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357"
- integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==
+ version "11.0.3"
+ resolved "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz"
+ integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
@@ -4746,6 +5000,37 @@
pify "^3.0.0"
slash "^1.0.0"
+globby@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
+ integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
+ dependencies:
+ "@types/glob" "^7.1.1"
+ array-union "^1.0.2"
+ dir-glob "^2.2.2"
+ fast-glob "^2.2.6"
+ glob "^7.1.3"
+ ignore "^4.0.3"
+ pify "^4.0.1"
+ slash "^2.0.0"
+
+got@^11.8.0:
+ version "11.8.2"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
+ integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==
+ dependencies:
+ "@sindresorhus/is" "^4.0.0"
+ "@szmarczak/http-timer" "^4.0.5"
+ "@types/cacheable-request" "^6.0.1"
+ "@types/responselike" "^1.0.0"
+ cacheable-lookup "^5.0.3"
+ cacheable-request "^7.0.1"
+ decompress-response "^6.0.0"
+ http2-wrapper "^1.0.0-beta.5.2"
+ lowercase-keys "^2.0.0"
+ p-cancelable "^2.0.0"
+ responselike "^2.0.0"
+
got@^5.0.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
@@ -4767,7 +5052,7 @@
unzip-response "^1.0.2"
url-parse-lax "^1.0.0"
-got@^6.7.1:
+got@^6.2.0, got@^6.7.1:
version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
@@ -4806,7 +5091,7 @@
got@^9.6.0:
version "9.6.0"
- resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
+ resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz"
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
dependencies:
"@sindresorhus/is" "^0.14.0"
@@ -4821,38 +5106,41 @@
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
- integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
+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:
+ version "4.2.6"
+ resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz"
+ integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
-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==
-
-grouped-queue@^0.3.0, grouped-queue@^0.3.3:
+grouped-queue@^0.3.0:
version "0.3.3"
resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c"
integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=
dependencies:
lodash "^4.17.2"
-gts@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/gts/-/gts-3.0.3.tgz#36716d87680c2d1a0e02867c91bb7169cede9369"
- integrity sha512-XHFGhDzoyaHDVHlhNfz369erxuSEIyVMtJoRAz8Dt2NpidG5pOJzI/44lWhsLVigph64TgAWPWBsBTQFCQ1mTw==
+grouped-queue@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-1.1.0.tgz#63e3f9ca90af952269d1d40879e41221eacc74cb"
+ integrity sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==
+ dependencies:
+ lodash "^4.17.15"
+
+gts@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/gts/-/gts-3.1.0.tgz#b27ce914191ed6ad34781968d0c77e0ed3042388"
+ integrity sha512-Pbj3ob1VR1IRlEVEBNtKoQ1wHOa8cZz62KEojK8Fn/qeS2ClWI4gLNfhek3lD68aZSmUEg8TFb6AHXIwUMgyqQ==
dependencies:
"@typescript-eslint/eslint-plugin" "^4.2.0"
"@typescript-eslint/parser" "^4.2.0"
chalk "^4.1.0"
eslint "^7.10.0"
- eslint-config-prettier "^6.12.0"
+ eslint-config-prettier "^7.0.0"
eslint-plugin-node "^11.1.0"
eslint-plugin-prettier "^3.1.4"
execa "^5.0.0"
inquirer "^7.3.3"
- meow "^8.0.0"
+ json5 "^2.1.3"
+ meow "^9.0.0"
ncp "^2.0.0"
prettier "^2.1.2"
rimraf "^3.0.2"
@@ -4869,9 +5157,9 @@
through2 "^2.0.1"
gulp-match@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e"
- integrity sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f"
+ integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==
dependencies:
minimatch "^3.0.3"
@@ -4887,9 +5175,9 @@
vinyl "^1.0.0"
gunzip-maybe@^1.3.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.1.tgz#39c72ed89d1b49ba708e18776500488902a52027"
- integrity sha512-qtutIKMthNJJgeHQS7kZ9FqDq59/Wn0G2HYCRNjpup7yKfVI6/eqwpmroyZGFoCYaG+sW6psNVb4zoLADHpp2g==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac"
+ integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==
dependencies:
browserify-zlib "^0.1.4"
is-deflate "^1.0.0"
@@ -4908,17 +5196,17 @@
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-har-validator@~5.1.0:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
- integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+har-validator@~5.1.0, har-validator@~5.1.3:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
- ajv "^6.5.5"
+ ajv "^6.12.3"
har-schema "^2.0.0"
hard-rejection@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
+ resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz"
integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
has-ansi@^2.0.0:
@@ -4928,6 +5216,11 @@
dependencies:
ansi-regex "^2.0.0"
+has-bigints@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz"
+ integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
+
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
@@ -4947,12 +5240,12 @@
has-flag@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbol-support-x@^1.4.1:
@@ -4960,15 +5253,10 @@
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
-has-symbols@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
- integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
-
-has-symbols@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+has-symbols@^1.0.1, has-symbols@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
+ integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has-to-string-tag-x@^1.2.0:
version "1.4.1"
@@ -4977,11 +5265,6 @@
dependencies:
has-symbol-support-x "^1.4.1"
-has-unicode@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
- integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
-
has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@@ -5015,12 +5298,12 @@
has-yarn@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
+ resolved "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
@@ -5038,14 +5321,14 @@
parse-passwd "^1.0.0"
hosted-git-info@^2.1.4:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
- integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+ version "2.8.9"
+ resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
-hosted-git-info@^3.0.6:
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.7.tgz#a30727385ea85acfcee94e0aad9e368c792e036c"
- integrity sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==
+hosted-git-info@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz"
+ integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==
dependencies:
lru-cache "^6.0.0"
@@ -5072,19 +5355,19 @@
relateurl "0.2.x"
uglify-js "3.4.x"
-htmlparser2@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-5.0.1.tgz#7daa6fc3e35d6107ac95a4fc08781f091664f6e7"
- integrity sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==
+htmlparser2@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz"
+ integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^2.0.1"
- domhandler "^3.3.0"
- domutils "^2.4.2"
+ domhandler "^4.0.0"
+ domutils "^2.5.2"
entities "^2.0.0"
http-cache-semantics@^4.0.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
+ resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
http-deceiver@^1.2.7:
@@ -5092,7 +5375,7 @@
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
-http-errors@1.7.2, http-errors@~1.7.2:
+http-errors@1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
@@ -5113,6 +5396,17 @@
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
+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==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.4"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
+
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"
@@ -5124,9 +5418,9 @@
micromatch "^2.3.11"
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==
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
@@ -5141,6 +5435,14 @@
jsprim "^1.2.2"
sshpk "^1.7.0"
+http2-wrapper@^1.0.0-beta.5.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
+ integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
+ dependencies:
+ quick-lru "^5.1.1"
+ resolve-alpn "^1.0.0"
+
https-proxy-agent@^2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
@@ -5149,64 +5451,54 @@
agent-base "^4.3.0"
debug "^3.1.0"
-https-proxy-agent@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
- integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
+https-proxy-agent@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
+ integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
dependencies:
- agent-base "^4.3.0"
- debug "^3.1.0"
+ agent-base "6"
+ debug "4"
+
+human-signals@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
+ integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
human-signals@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
-iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
+iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
-ieee754@^1.1.4:
- version "1.1.13"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
- integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
-
-ignore-walk@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
- integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
- dependencies:
- minimatch "^3.0.4"
+ieee754@^1.1.13:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^3.3.5:
version "3.3.10"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
-ignore@^4.0.6:
+ignore@^4.0.3, ignore@^4.0.6:
version "4.0.6"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.1.1, ignore@^5.1.4:
version "5.1.8"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
+ resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
-import-fresh@^3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
- integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-import-fresh@^3.2.1:
+import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
@@ -5214,12 +5506,12 @@
import-lazy@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
+ resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
imurmurhash@^0.1.4:
version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
indent-string@^2.1.0:
@@ -5231,7 +5523,7 @@
indent-string@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
indent@0.0.2:
@@ -5246,15 +5538,15 @@
inflight@^1.0.4:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.3:
@@ -5262,15 +5554,15 @@
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-ini@1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
- integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
+ini@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz"
+ integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
ini@^1.3.4, ini@~1.3.0:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
- integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+ version "1.3.8"
+ resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inquirer@^1.0.2:
version "1.2.3"
@@ -5292,28 +5584,9 @@
strip-ansi "^3.0.0"
through "^2.3.6"
-inquirer@^6.0.0:
- version "6.4.1"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b"
- integrity sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw==
- dependencies:
- ansi-escapes "^3.2.0"
- chalk "^2.4.2"
- cli-cursor "^2.1.0"
- cli-width "^2.0.0"
- external-editor "^3.0.3"
- figures "^2.0.0"
- lodash "^4.17.11"
- mute-stream "0.0.7"
- run-async "^2.2.0"
- rxjs "^6.4.0"
- string-width "^2.1.0"
- strip-ansi "^5.1.0"
- through "^2.3.6"
-
-inquirer@^7.3.3:
+inquirer@^7.1.0, inquirer@^7.3.3:
version "7.3.3"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
+ resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
@@ -5331,9 +5604,9 @@
through "^2.3.6"
interpret@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
- integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
intersect@^1.0.1:
version "1.0.1"
@@ -5347,10 +5620,10 @@
dependencies:
loose-envify "^1.0.0"
-ipaddr.js@1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
- integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
is-accessor-descriptor@^0.1.6:
version "0.1.6"
@@ -5368,7 +5641,7 @@
is-arrayish@^0.2.1:
version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
is-arrayish@^0.3.1:
@@ -5376,6 +5649,11 @@
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+is-bigint@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz"
+ integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==
+
is-binary-path@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
@@ -5383,15 +5661,22 @@
dependencies:
binary-extensions "^1.0.0"
-is-buffer@^1.1.5, is-buffer@~1.1.1:
+is-boolean-object@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz"
+ integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==
+ dependencies:
+ call-bind "^1.0.0"
+
+is-buffer@^1.1.5, is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
-is-callable@^1.1.4, is-callable@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
- integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
+is-callable@^1.1.4, is-callable@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz"
+ integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
is-ci@^1.0.10:
version "1.2.1"
@@ -5402,14 +5687,14 @@
is-ci@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
+ resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz"
integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
dependencies:
ci-info "^2.0.0"
-is-core-module@^2.1.0:
+is-core-module@^2.2.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
+ resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz"
integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
dependencies:
has "^1.0.3"
@@ -5430,7 +5715,7 @@
is-date-object@^1.0.1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
+ resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz"
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
is-deflate@^1.0.0:
@@ -5487,15 +5772,13 @@
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"
+ resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-finite@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
- integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
- dependencies:
- number-is-nan "^1.0.0"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
+ integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
@@ -5506,12 +5789,12 @@
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-glob@^2.0.0, is-glob@^2.0.1:
@@ -5530,7 +5813,7 @@
is-glob@^4.0.0, is-glob@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+ resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
@@ -5548,17 +5831,17 @@
global-dirs "^0.1.0"
is-path-inside "^1.0.0"
-is-installed-globally@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
- integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
+is-installed-globally@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz"
+ integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==
dependencies:
- global-dirs "^2.0.1"
- is-path-inside "^3.0.1"
+ global-dirs "^3.0.0"
+ is-path-inside "^3.0.2"
-is-negative-zero@^2.0.0:
+is-negative-zero@^2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
+ resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz"
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
is-npm@^1.0.0:
@@ -5568,9 +5851,14 @@
is-npm@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8"
+ resolved "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz"
integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==
+is-number-object@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz"
+ integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
+
is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
@@ -5592,7 +5880,7 @@
is-number@^7.0.0:
version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-obj@^1.0.0:
@@ -5602,13 +5890,13 @@
is-obj@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
+ resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz"
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
is-object@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
- integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf"
+ integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==
is-path-cwd@^1.0.0:
version "1.0.0"
@@ -5629,14 +5917,14 @@
dependencies:
path-is-inside "^1.0.1"
-is-path-inside@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
- integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
+is-path-inside@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+ resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz"
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
@@ -5646,12 +5934,10 @@
dependencies:
isobject "^3.0.1"
-is-plain-object@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
- integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
- dependencies:
- isobject "^4.0.0"
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-posix-bracket@^0.1.0:
version "0.1.1"
@@ -5659,36 +5945,32 @@
integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
is-potential-custom-element-name@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
- integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
+ integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
-is-promise@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
- integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
-
is-redirect@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
-is-regex@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
- integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
+is-regex@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz"
+ integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==
dependencies:
+ call-bind "^1.0.2"
has-symbols "^1.0.1"
is-retry-allowed@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
- integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
+ integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
is-scoped@^1.0.0:
version "1.0.0"
@@ -5704,27 +5986,27 @@
is-stream@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
is-string@^1.0.5:
version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
+ resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz"
integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
-is-symbol@^1.0.2:
+is-symbol@^1.0.2, is-symbol@^1.0.3:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
+ resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz"
integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
dependencies:
has-symbols "^1.0.1"
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-is-utf8@^0.2.0:
+is-utf8@^0.2.0, is-utf8@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
@@ -5746,7 +6028,7 @@
is-yarn-global@^0.3.0:
version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
+ resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz"
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
isarray@0.0.1:
@@ -5756,7 +6038,7 @@
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isarray@2.0.1:
@@ -5771,9 +6053,14 @@
dependencies:
buffer-alloc "^1.2.0"
+isbinaryfile@^4.0.0:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b"
+ integrity sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==
+
isexe@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
isobject@^2.0.0:
@@ -5788,24 +6075,19 @@
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-isobject@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
- integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
-
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-istextorbinary@^2.2.1:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.5.1.tgz#14a33824cf6b9d5d7743eac1be2bd2c310d0ccbd"
- integrity sha512-pv/JNPWnfpwGjPx7JrtWTwsWsxkrK3fNzcEVnt92YKEIErps4Fsk49+qzCe9iQF2hjqK8Naqf8P9kzoeCuQI1g==
+istextorbinary@^2.2.1, istextorbinary@^2.5.1:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab"
+ integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==
dependencies:
binaryextensions "^2.1.2"
- editions "^2.1.3"
- textextensions "^2.4.0"
+ editions "^2.2.0"
+ textextensions "^2.5.0"
isurl@^1.0.0-alpha5:
version "1.0.0"
@@ -5815,9 +6097,19 @@
has-to-string-tag-x "^1.2.0"
is-object "^1.0.1"
+jake@^10.6.1:
+ version "10.8.2"
+ resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b"
+ integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==
+ dependencies:
+ async "0.9.x"
+ chalk "^2.4.2"
+ filelist "^1.0.1"
+ minimatch "^3.0.4"
+
"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"
+ resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-tokens@^3.0.2:
@@ -5826,9 +6118,9 @@
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
js-yaml@^3.13.1:
- version "3.13.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
- integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+ version "3.14.1"
+ resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -5840,7 +6132,7 @@
jsdoctypeparser@^9.0.0:
version "9.0.0"
- resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz#8c97e2fb69315eb274b0f01377eaa5c940bd7b26"
+ resolved "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz"
integrity sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==
jsesc@^1.3.0:
@@ -5860,9 +6152,14 @@
json-buffer@3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
+ resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
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"
@@ -5870,14 +6167,19 @@
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
- resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
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"
+ resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@@ -5885,7 +6187,7 @@
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json-stringify-safe@~5.0.1:
@@ -5895,22 +6197,27 @@
json5@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+ resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz"
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
dependencies:
minimist "^1.2.0"
-json5@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
- integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==
+json5@^2.1.2, json5@^2.1.3:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz"
+ integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
- minimist "^1.2.0"
+ minimist "^1.2.5"
+
+jsonparse@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+ integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
jsonschema@^1.1.0, jsonschema@^1.1.1:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.4.tgz#a46bac5d3506a254465bc548876e267c6d0d6464"
- integrity sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2"
+ integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==
jsprim@^1.2.2:
version "1.4.1"
@@ -5924,11 +6231,18 @@
keyv@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
+ resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
+keyv@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
+ integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
+ dependencies:
+ json-buffer "3.0.1"
+
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"
@@ -5948,22 +6262,15 @@
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
-kind-of@^6.0.0, kind-of@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
- integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
-
-kind-of@^6.0.3:
+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
version "6.0.3"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-kuler@1.0.x:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
- integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==
- dependencies:
- colornames "^1.1.1"
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
latest-version@^2.0.0:
version "2.0.0"
@@ -5981,15 +6288,15 @@
latest-version@^5.1.0:
version "5.1.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
+ resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz"
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
dependencies:
package-json "^6.3.0"
launchpad@^0.7.0:
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.4.tgz#08a7a38f48b963e73dc68be84f9f8f974c46c26b"
- integrity sha512-3KDFHbvXm52CEA4vSQ9kz4vwAxH7SANj2k6SJcE6LCpmMJFOu6wCpZwXb+pq9kSDknl5XInBWeOl40i00P6wTQ==
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.5.tgz#a16950c937572f10ef01c9be945a96f7aef8e427"
+ integrity sha512-gsYFgT8XKL3X2XZHPPPrgwM0JqeQwGpSWnzg7EYadBY3MirbQrTVq6L4fm6l7UE2T+7gnfuhiGkKr/xxuU/fdw==
dependencies:
async "^2.0.1"
browserstack "^1.2.0"
@@ -6000,6 +6307,13 @@
rimraf "^3.0.0"
underscore "^1.8.3"
+lazy-cache@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
+ integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
+ dependencies:
+ set-getter "^0.1.0"
+
lazy-req@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
@@ -6014,7 +6328,7 @@
levn@^0.4.1:
version "0.4.1"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
@@ -6022,7 +6336,7 @@
lines-and-columns@^1.1.6:
version "1.1.6"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+ resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
load-json-file@^1.0.0:
@@ -6038,7 +6352,7 @@
load-json-file@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+ resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz"
integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
dependencies:
graceful-fs "^4.1.2"
@@ -6058,7 +6372,7 @@
locate-path@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz"
integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
dependencies:
p-locate "^2.0.0"
@@ -6074,7 +6388,7 @@
locate-path@^5.0.0:
version "5.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
@@ -6089,6 +6403,11 @@
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+lodash.clonedeep@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
+ integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
+
lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
@@ -6101,7 +6420,7 @@
lodash.flatten@^4.4.0:
version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+ resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz"
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
lodash.get@^4.4.2:
@@ -6119,6 +6438,16 @@
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+lodash.mapvalues@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
+ integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
lodash.padend@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
@@ -6129,11 +6458,6 @@
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
-lodash.some@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
- integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
-
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@@ -6154,6 +6478,11 @@
dependencies:
lodash._reinterpolate "^3.0.0"
+lodash.truncate@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz"
+ integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
+
lodash.union@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
@@ -6169,20 +6498,10 @@
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-lodash@^4.0.0, lodash@^4.16.6, lodash@^4.17.14, lodash@^4.17.15:
- version "4.17.15"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
- integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
-
-lodash@^4.11.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0:
- version "4.17.12"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.12.tgz#a712c74fdc31f7ecb20fe44f157d802d208097ef"
- integrity sha512-+CiwtLnsJhX03p20mwXuvhoebatoh5B3tt+VvYlrPgZC1g36y+RRbkufX95Xa+X4I59aWEacDFYwnJZiyBh9gA==
-
-lodash@^4.17.19, lodash@^4.17.20:
- version "4.17.20"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
- integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
+lodash@^4.0.0, lodash@^4.11.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0:
+ version "4.17.21"
+ resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^1.0.0, log-symbols@^1.0.1:
version "1.0.2"
@@ -6209,14 +6528,14 @@
ms "^2.1.1"
triple-beam "^1.2.0"
-logform@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360"
- integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==
+logform@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2"
+ integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==
dependencies:
colors "^1.2.1"
fast-safe-stringify "^2.0.4"
- fecha "^2.3.3"
+ fecha "^4.2.0"
ms "^2.1.1"
triple-beam "^1.3.0"
@@ -6227,7 +6546,7 @@
long@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
+ resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
loose-envify@^1.0.0:
@@ -6252,12 +6571,12 @@
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
+ resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowercase-keys@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+ resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^4.0.1, lru-cache@^4.0.2:
@@ -6270,15 +6589,15 @@
lru-cache@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
macos-release@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
- integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.4.1.tgz#64033d0ec6a5e6375155a74b1a1eba8e509820ac"
+ integrity sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==
magic-string@^0.22.4:
version "0.22.5"
@@ -6296,7 +6615,7 @@
make-dir@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz"
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
dependencies:
semver "^6.0.0"
@@ -6308,13 +6627,13 @@
map-obj@^1.0.0, map-obj@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+ resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
map-obj@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
- integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
+ version "4.2.1"
+ resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz"
+ integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==
map-visit@^1.0.0:
version "1.0.0"
@@ -6336,13 +6655,13 @@
integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
md5@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
- integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
+ integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
- charenc "~0.0.1"
- crypt "~0.0.1"
- is-buffer "~1.1.1"
+ charenc "0.0.2"
+ crypt "0.0.2"
+ is-buffer "~1.1.6"
media-typer@0.3.0:
version "0.3.0"
@@ -6366,16 +6685,50 @@
through2 "^2.0.0"
vinyl "^2.0.1"
-mem-fs@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc"
- integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=
+mem-fs-editor@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-6.0.0.tgz#d63607cf0a52fe6963fc376c6a7aa52db3edabab"
+ integrity sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==
dependencies:
- through2 "^2.0.0"
- vinyl "^1.1.0"
- vinyl-file "^2.0.0"
+ commondir "^1.0.1"
+ deep-extend "^0.6.0"
+ ejs "^2.6.1"
+ glob "^7.1.4"
+ globby "^9.2.0"
+ isbinaryfile "^4.0.0"
+ mkdirp "^0.5.0"
+ multimatch "^4.0.0"
+ rimraf "^2.6.3"
+ through2 "^3.0.1"
+ vinyl "^2.2.0"
-meow@^3.1.0, meow@^3.7.0:
+mem-fs-editor@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-7.1.0.tgz#2a16f143228df87bf918874556723a7ee73bfe88"
+ integrity sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==
+ dependencies:
+ commondir "^1.0.1"
+ deep-extend "^0.6.0"
+ ejs "^3.1.5"
+ glob "^7.1.4"
+ globby "^9.2.0"
+ isbinaryfile "^4.0.0"
+ mkdirp "^1.0.0"
+ multimatch "^4.0.0"
+ rimraf "^3.0.0"
+ through2 "^3.0.2"
+ vinyl "^2.2.1"
+
+mem-fs@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.2.0.tgz#5f29b2d02a5875cd14cd836c388385892d556cde"
+ integrity sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==
+ dependencies:
+ through2 "^3.0.0"
+ vinyl "^2.0.1"
+ vinyl-file "^3.0.0"
+
+meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
@@ -6391,13 +6744,14 @@
redent "^1.0.0"
trim-newlines "^1.0.0"
-meow@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-8.0.0.tgz#1aa10ee61046719e334ffdc038bb5069250ec99a"
- integrity sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==
+meow@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz"
+ integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==
dependencies:
"@types/minimist" "^1.2.0"
camelcase-keys "^6.2.2"
+ decamelize "^1.2.0"
decamelize-keys "^1.1.0"
hard-rejection "^2.1.0"
minimist-options "4.1.0"
@@ -6422,17 +6776,12 @@
merge-stream@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-merge2@^1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
- integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
-
-merge2@^1.3.0:
+merge2@^1.2.3, merge2@^1.3.0:
version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
methods@~1.1.2:
@@ -6480,35 +6829,23 @@
micromatch@^4.0.2:
version "4.0.2"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
+ resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz"
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
dependencies:
braces "^3.0.1"
picomatch "^2.0.5"
-mime-db@1.40.0, mime-db@^1.28.0:
- version "1.40.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
- integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+mime-db@1.47.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
+ version "1.47.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
+ integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
-mime-db@1.43.0, "mime-db@>= 1.43.0 < 2":
- version "1.43.0"
- 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:
- version "2.1.24"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
- integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
+ version "2.1.30"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
+ integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
dependencies:
- mime-db "1.40.0"
-
-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==
- dependencies:
- mime-db "1.43.0"
+ mime-db "1.47.0"
mime@1.4.1:
version "1.4.1"
@@ -6521,28 +6858,28 @@
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.3.1:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
- integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
-
-mimic-fn@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
- integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
+ integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
mimic-fn@^2.1.0:
version "2.1.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+ resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+mimic-response@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+ integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
min-indent@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
+ resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
minimalistic-assert@^1.0.0:
@@ -6559,44 +6896,29 @@
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
minimist-options@4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
+ resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz"
integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
dependencies:
arrify "^1.0.1"
is-plain-obj "^1.1.0"
kind-of "^6.0.3"
-minimist@0.0.8, minimist@~0.0.1:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
- integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+minimist@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.1.tgz#827ba4e7593464e7c221e8c5bed930904ee2c455"
+ integrity sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==
-minimist@^1.1.3, minimist@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
- integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
-
-minipass@^2.2.1, minipass@^2.3.4:
- version "2.3.5"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
- integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
- dependencies:
- safe-buffer "^5.1.2"
- yallist "^3.0.0"
-
-minizlib@^1.1.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
- integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
- dependencies:
- minipass "^2.2.1"
+minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mixin-deep@^1.2.0:
version "1.3.2"
@@ -6607,11 +6929,21 @@
is-extendable "^1.0.1"
mkdirp@^0.5.0, mkdirp@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
- integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+ version "0.5.5"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
+ integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
- minimist "0.0.8"
+ minimist "^1.2.5"
+
+mkdirp@^1.0.0, mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+moment@^2.15.1, moment@^2.24.0:
+ version "2.29.1"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
+ integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
mout@^1.0.0:
version "1.2.2"
@@ -6620,7 +6952,7 @@
ms@2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.1:
@@ -6628,11 +6960,16 @@
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-ms@2.1.2, ms@^2.1.1:
+ms@2.1.2:
version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
multer@^1.3.0:
version "1.4.2"
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
@@ -6657,6 +6994,17 @@
arrify "^1.0.0"
minimatch "^3.0.0"
+multimatch@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
+ integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
+ dependencies:
+ "@types/minimatch" "^3.0.3"
+ array-differ "^3.0.0"
+ array-union "^2.1.0"
+ arrify "^2.0.1"
+ minimatch "^3.0.4"
+
multipipe@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
@@ -6670,14 +7018,9 @@
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=
-mute-stream@0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
- integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
-
mute-stream@0.0.8:
version "0.0.8"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
mz@^2.4.0, mz@^2.6.0:
@@ -6690,9 +7033,9 @@
thenify-all "^1.0.0"
nan@^2.12.1:
- version "2.14.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
- integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+ version "2.14.2"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
+ integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
nanomatch@^1.2.9:
version "1.2.13"
@@ -6718,23 +7061,14 @@
natural-compare@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
ncp@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
+ resolved "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz"
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
-needle@^2.2.1:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.0.tgz#ce3fea21197267bacb310705a7bbe24f2a3a3492"
- integrity sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==
- dependencies:
- debug "^4.1.0"
- iconv-lite "^0.4.4"
- sax "^1.2.4"
-
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
@@ -6752,26 +7086,15 @@
dependencies:
lower-case "^1.1.1"
-node-fetch@^2.3.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-fetch@^2.6.0, node-fetch@^2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+ integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
-node-pre-gyp@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
- integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
- dependencies:
- detect-libc "^1.0.2"
- mkdirp "^0.5.1"
- needle "^2.2.1"
- nopt "^4.0.1"
- npm-packlist "^1.1.6"
- npmlog "^4.0.2"
- rc "^1.2.7"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar "^4"
+node-releases@^1.1.70:
+ version "1.1.71"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
+ integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
node-status-codes@^1.0.0:
version "1.0.0"
@@ -6786,17 +7109,9 @@
chalk "~0.4.0"
underscore "~1.6.0"
-nopt@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
- integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
- dependencies:
- abbrev "1"
- osenv "^0.1.4"
-
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
version "2.5.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
dependencies:
hosted-git-info "^2.1.4"
@@ -6805,13 +7120,13 @@
validate-npm-package-license "^3.0.1"
normalize-package-data@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.0.tgz#1f8a7c423b3d2e85eb36985eaf81de381d01301a"
- integrity sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz"
+ integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==
dependencies:
- hosted-git-info "^3.0.6"
- resolve "^1.17.0"
- semver "^7.3.2"
+ hosted-git-info "^4.0.1"
+ resolve "^1.20.0"
+ semver "^7.3.4"
validate-npm-package-license "^3.0.1"
normalize-path@^2.0.0, normalize-path@^2.0.1:
@@ -6828,21 +7143,20 @@
normalize-url@^4.1.0:
version "4.5.0"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
+ resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
-npm-bundled@^1.0.1:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
- integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
-
-npm-packlist@^1.1.6:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
- integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
+npm-api@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/npm-api/-/npm-api-1.0.1.tgz#3def9b51afedca57db14ca0c970d92442d21c9c5"
+ integrity sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==
dependencies:
- ignore-walk "^3.0.1"
- npm-bundled "^1.0.1"
+ JSONStream "^1.3.5"
+ clone-deep "^4.0.1"
+ download-stats "^0.3.4"
+ moment "^2.24.0"
+ node-fetch "^2.6.0"
+ paged-request "^2.0.1"
npm-run-path@^2.0.0:
version "2.0.2"
@@ -6851,23 +7165,13 @@
dependencies:
path-key "^2.0.0"
-npm-run-path@^4.0.1:
+npm-run-path@^4.0.0, npm-run-path@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
-npmlog@^4.0.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
- integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
- dependencies:
- are-we-there-yet "~1.1.2"
- console-control-strings "~1.1.0"
- gauge "~2.7.3"
- set-blocking "~2.0.0"
-
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@@ -6883,11 +7187,6 @@
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-object-component@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
- integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
-
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -6897,14 +7196,14 @@
define-property "^0.2.5"
kind-of "^3.0.3"
-object-inspect@^1.8.0:
+object-inspect@^1.9.0:
version "1.9.0"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
+ resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz"
integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
-object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object-visit@^1.0.0:
@@ -6914,19 +7213,9 @@
dependencies:
isobject "^3.0.0"
-object.assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
- dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
-
-object.assign@^4.1.1:
+object.assign@^4.1.0, object.assign@^4.1.2:
version "4.1.2"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+ resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
dependencies:
call-bind "^1.0.0"
@@ -6950,13 +7239,13 @@
isobject "^3.0.1"
object.values@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.2.tgz#7a2015e06fcb0f546bd652486ce8583a4731c731"
- integrity sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==
+ version "1.1.3"
+ resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz"
+ integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==
dependencies:
- call-bind "^1.0.0"
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.18.0-next.1"
+ es-abstract "^1.18.0-next.2"
has "^1.0.3"
obuf@^1.0.0, obuf@^1.1.1:
@@ -6983,31 +7272,26 @@
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"
+ resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
-one-time@0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
- integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
-onetime@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
- integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
- dependencies:
- mimic-fn "^1.0.0"
-
onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
@@ -7019,17 +7303,9 @@
dependencies:
object-assign "^4.0.1"
-optimist@^0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
- integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
- dependencies:
- minimist "~0.0.1"
- wordwrap "~0.0.2"
-
optionator@^0.9.1:
version "0.9.1"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+ resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "^0.1.3"
@@ -7052,7 +7328,7 @@
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-os-name@^3.0.0:
+os-name@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
@@ -7067,10 +7343,10 @@
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, 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"
+ resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4:
+osenv@^0.1.0, osenv@^0.1.3:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@@ -7085,9 +7361,14 @@
p-cancelable@^1.0.0:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
+ resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
+p-cancelable@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.0.tgz#4d51c3b91f483d02a0d300765321fca393d758dd"
+ integrity sha512-HAZyB3ZodPo+BDpb4/Iu7Jv4P6cSazBz9ZM0ChhEXp70scx834aWCEjQRwgt41UzzejUAPdbqqONfRWTPYrPAQ==
+
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@@ -7095,28 +7376,21 @@
p-limit@^1.1.0:
version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz"
integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
dependencies:
p-try "^1.0.0"
-p-limit@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
- integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
- dependencies:
- p-try "^2.0.0"
-
-p-limit@^2.2.0:
+p-limit@^2.0.0, p-limit@^2.2.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
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"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz"
integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
dependencies:
p-limit "^1.1.0"
@@ -7130,7 +7404,7 @@
p-locate@^4.1.0:
version "4.1.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
@@ -7149,12 +7423,12 @@
p-try@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+ resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz"
integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
p-try@^2.0.0, p-try@^2.1.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
package-json@^2.0.0:
@@ -7179,7 +7453,7 @@
package-json@^6.3.0:
version "6.5.0"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
+ resolved "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz"
integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
dependencies:
got "^9.6.0"
@@ -7187,6 +7461,13 @@
registry-url "^5.0.0"
semver "^6.2.0"
+paged-request@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/paged-request/-/paged-request-2.0.2.tgz#4d621a08b8d6bee4440a0a92112354eeece5b5b0"
+ integrity sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==
+ dependencies:
+ axios "^0.21.1"
+
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
@@ -7201,7 +7482,7 @@
parent-module@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
@@ -7218,7 +7499,7 @@
parse-json@^2.1.0, parse-json@^2.2.0:
version "2.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
dependencies:
error-ex "^1.2.0"
@@ -7232,9 +7513,9 @@
json-parse-better-errors "^1.0.1"
parse-json@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
- integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
error-ex "^1.3.1"
@@ -7251,19 +7532,15 @@
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
-parseqs@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
- integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
- dependencies:
- better-assert "~1.0.0"
+parseqs@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5"
+ integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==
-parseuri@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
- integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
- dependencies:
- better-assert "~1.0.0"
+parseuri@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
+ integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
parseurl@~1.3.3:
version "1.3.3"
@@ -7289,17 +7566,17 @@
path-exists@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
path-exists@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
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"
+ resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-is-inside@^1.0.1, path-is-inside@^1.0.2:
@@ -7314,12 +7591,12 @@
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+ resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
path-to-regexp@0.1.7:
@@ -7327,14 +7604,7 @@
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
-path-to-regexp@^1.0.1:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
- integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
- dependencies:
- isarray "0.0.1"
-
-path-to-regexp@^1.7.0:
+path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
@@ -7352,7 +7622,7 @@
path-type@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+ resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz"
integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
dependencies:
pify "^2.0.0"
@@ -7366,7 +7636,7 @@
path-type@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
peek-stream@^1.1.0:
@@ -7379,14 +7649,14 @@
through2 "^2.0.3"
pem@^1.8.3:
- version "1.14.3"
- resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.3.tgz#347e5a5c194a5f7612b88083e45042fcc4fb4901"
- integrity sha512-Q+AMVMD3fzeVvZs5PHeI+pVt0hgZY2fjhkliBW43qyONLgCXPVk1ryim43F9eupHlNGLJNT5T/NNrzhUdiC5Zg==
+ version "1.14.4"
+ resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.4.tgz#a68c70c6e751ccc5b3b5bcd7af78b0aec1177ff9"
+ integrity sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g==
dependencies:
es6-promisify "^6.0.0"
md5 "^2.2.1"
os-tmpdir "^1.0.1"
- which "^1.3.1"
+ which "^2.0.2"
pend@~1.2.0:
version "1.2.0"
@@ -7400,12 +7670,12 @@
picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
pify@^3.0.0:
@@ -7432,7 +7702,7 @@
pkg-dir@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz"
integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
dependencies:
find-up "^2.1.0"
@@ -7594,7 +7864,7 @@
polymer-cli@^1.9.11:
version "1.9.11"
- resolved "https://registry.yarnpkg.com/polymer-cli/-/polymer-cli-1.9.11.tgz#0b5310732b787e07b811af96627ef0fd1263f5da"
+ resolved "https://registry.npmjs.org/polymer-cli/-/polymer-cli-1.9.11.tgz"
integrity sha512-tiURjHDCOUUtDVPuVYvrfFI9PXe4OOUmBbn6Sg5GJNQ2POtP7r7hv+I5yI8P9qsxmalHTa19chVtf5/t9IBXDg==
dependencies:
"@octokit/rest" "^16.2.0"
@@ -7728,7 +7998,7 @@
prelude-ls@^1.2.1:
version "1.2.1"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prepend-http@^1.0.1:
@@ -7738,7 +8008,7 @@
prepend-http@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
+ resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
preserve@^0.2.0:
@@ -7748,19 +8018,14 @@
prettier-linter-helpers@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
-prettier@2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
- integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
-
-prettier@^2.1.2:
+prettier@2.2.1, prettier@^2.1.2:
version "2.2.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
+ resolved "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
pretty-bytes@^4.0.2:
@@ -7768,15 +8033,10 @@
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
-pretty-bytes@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.2.0.tgz#96c92c6e95a0b35059253fb33c03e260d40f5a1f"
- integrity sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==
-
-private@^0.1.6:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
- integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+pretty-bytes@^5.1.0, pretty-bytes@^5.2.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
+ integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
version "2.0.1"
@@ -7785,12 +8045,12 @@
progress@2.0.3, progress@^2.0.0:
version "2.0.3"
- resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
protobufjs@6.8.8:
version "6.8.8"
- resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
+ resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz"
integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
@@ -7808,22 +8068,22 @@
long "^4.0.0"
proxy-addr@~2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
- integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
+ integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
dependencies:
forwarded "~0.1.2"
- ipaddr.js "1.9.0"
+ ipaddr.js "1.9.1"
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-psl@^1.1.24:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6"
- integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==
+psl@^1.1.24, 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@^1.0.0:
version "1.0.3"
@@ -7843,7 +8103,7 @@
pump@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
@@ -7863,14 +8123,14 @@
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"
+ resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
pupa@^2.1.1:
version "2.1.1"
- resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
+ resolved "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz"
integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
dependencies:
escape-goat "^2.0.0"
@@ -7890,11 +8150,21 @@
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
quick-lru@^4.0.1:
version "4.0.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
+ resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
randomatic@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
@@ -7919,9 +8189,9 @@
iconv-lite "0.4.24"
unpipe "1.0.0"
-rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8:
+rc@^1.0.1, rc@^1.1.6, rc@^1.2.8:
version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
dependencies:
deep-extend "^0.6.0"
@@ -7937,7 +8207,7 @@
pinkie-promise "^2.0.0"
readable-stream "^2.0.0"
-read-chunk@^3.0.0:
+read-chunk@^3.0.0, read-chunk@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
@@ -7955,7 +8225,7 @@
read-pkg-up@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
+ resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz"
integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
dependencies:
find-up "^2.0.0"
@@ -7969,9 +8239,17 @@
find-up "^3.0.0"
read-pkg "^3.0.0"
+read-pkg-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-5.0.0.tgz#b6a6741cb144ed3610554f40162aa07a6db621b8"
+ integrity sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==
+ dependencies:
+ find-up "^3.0.0"
+ read-pkg "^5.0.0"
+
read-pkg-up@^7.0.1:
version "7.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz"
integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
dependencies:
find-up "^4.1.0"
@@ -7989,7 +8267,7 @@
read-pkg@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+ resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz"
integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
dependencies:
load-json-file "^2.0.0"
@@ -8005,9 +8283,9 @@
normalize-package-data "^2.3.2"
path-type "^3.0.0"
-read-pkg@^5.2.0:
+read-pkg@^5.0.0, read-pkg@^5.2.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz"
integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
dependencies:
"@types/normalize-package-data" "^2.4.0"
@@ -8025,18 +8303,14 @@
isarray "0.0.1"
string_decoder "~0.10.x"
-"readable-stream@2 || 3", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
- integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+ integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
"readable-stream@>=1.0.33-1 <1.1.0-0":
version "1.0.34"
@@ -8048,7 +8322,7 @@
isarray "0.0.1"
string_decoder "~0.10.x"
-readable-stream@^2.2.2, readable-stream@^2.2.9:
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -8061,15 +8335,6 @@
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
- integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
- dependencies:
- inherits "^2.0.3"
- string_decoder "^1.1.1"
- util-deprecate "^1.0.1"
-
readdirp@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@@ -8096,7 +8361,7 @@
redent@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
+ resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz"
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
dependencies:
indent-string "^4.0.0"
@@ -8107,29 +8372,34 @@
resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
-regenerate-unicode-properties@^8.0.2:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
- integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+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"
- integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
+ integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-regenerator-transform@^0.14.0:
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf"
- integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==
+regenerator-runtime@^0.13.4:
+ version "0.13.7"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+ integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
+
+regenerator-transform@^0.14.2:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
+ integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
dependencies:
- private "^0.1.6"
+ "@babel/runtime" "^7.8.4"
regex-cache@^0.4.2:
version "0.4.4"
@@ -8148,24 +8418,24 @@
regexpp@^3.0.0, regexpp@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
+ resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
-regexpu-core@^4.5.4:
- version "4.5.4"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
- integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
+regexpu-core@^4.7.1:
+ version "4.7.1"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
+ integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
dependencies:
regenerate "^1.4.0"
- regenerate-unicode-properties "^8.0.2"
- regjsgen "^0.5.0"
- regjsparser "^0.6.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.1.0"
+ unicode-match-property-value-ecmascript "^1.2.0"
regextras@^0.7.1:
version "0.7.1"
- resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.7.1.tgz#be95719d5f43f9ef0b9fa07ad89b7c606995a3b2"
+ resolved "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz"
integrity sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==
registry-auth-token@^3.0.1:
@@ -8178,7 +8448,7 @@
registry-auth-token@^4.0.0:
version "4.2.1"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250"
+ resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz"
integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==
dependencies:
rc "^1.2.8"
@@ -8192,20 +8462,20 @@
registry-url@^5.0.0:
version "5.1.0"
- resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
+ resolved "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz"
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
dependencies:
rc "^1.2.8"
-regjsgen@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd"
- integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==
+regjsgen@^0.5.1:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
+ integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
-regjsparser@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c"
- integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==
+regjsparser@^0.6.4:
+ version "0.6.9"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
+ integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
dependencies:
jsesc "~0.5.0"
@@ -8220,9 +8490,9 @@
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
repeat-element@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
- integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
+ integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
repeat-string@^1.5.2, repeat-string@^1.6.1:
version "1.6.1"
@@ -8242,11 +8512,11 @@
integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
replace-ext@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
- integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
+ integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
-request@2.88.0, request@^2.72.0, request@^2.85.0:
+request@2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -8272,6 +8542,37 @@
tunnel-agent "^0.6.0"
uuid "^3.3.2"
+request@^2.72.0, request@^2.85.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-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
requirejs@^2.3.4:
version "2.3.6"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
@@ -8282,6 +8583,11 @@
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+resolve-alpn@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.1.1.tgz#4a006a7d533c81a5dd04681612090fde227cd6e1"
+ integrity sha512-0KbFjFPR2bnJhNx1t8Ad6RqVc8+QPJC4y561FYyC/Q/6OzB3fhUzB5PEgitYhPK6aifwR5gXBSnDMllaDWixGQ==
+
resolve-dir@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
@@ -8300,7 +8606,7 @@
resolve-from@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve-url@^0.2.1:
@@ -8308,42 +8614,28 @@
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
- integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.5.0:
+ version "1.20.0"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz"
+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
- path-parse "^1.0.6"
-
-resolve@^1.10.1:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
- integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
- dependencies:
- path-parse "^1.0.6"
-
-resolve@^1.13.1, resolve@^1.17.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
- integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
- dependencies:
- is-core-module "^2.1.0"
- path-parse "^1.0.6"
-
-resolve@^1.5.0:
- version "1.14.2"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2"
- integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==
- dependencies:
+ is-core-module "^2.2.0"
path-parse "^1.0.6"
responselike@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
+ resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
dependencies:
lowercase-keys "^1.0.0"
+responselike@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
+ integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
+ dependencies:
+ lowercase-keys "^2.0.0"
+
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@@ -8352,17 +8644,9 @@
exit-hook "^1.0.0"
onetime "^1.0.0"
-restore-cursor@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
- integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
- dependencies:
- onetime "^2.0.0"
- signal-exit "^3.0.2"
-
restore-cursor@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz"
integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
dependencies:
onetime "^5.1.0"
@@ -8375,96 +8659,79 @@
reusify@^1.0.4:
version "1.0.4"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2:
+rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@^3.0.0, rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@~2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
dependencies:
glob "^7.1.3"
-rimraf@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
- integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
- dependencies:
- glob "^7.1.3"
-
-rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
-rimraf@~2.2.6:
- version "2.2.8"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
- integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=
-
rollup@^1.3.0:
- version "1.16.7"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.16.7.tgz#4b539ca22465df39f6c963d2001d95f6527e97e1"
- integrity sha512-P3GVcbVSLLjHWFLKGerYRe3Q/yggRXmTZFx/4WZf4wzGwO6hAg5jyMAFMQKc0dts8rFID4BQngfoz6yQbI7iMQ==
+ version "1.32.1"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4"
+ integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==
dependencies:
- "@types/estree" "0.0.39"
- "@types/node" "^12.0.10"
- acorn "^6.1.1"
+ "@types/estree" "*"
+ "@types/node" "*"
+ acorn "^7.1.0"
-rollup@^2.3.4:
- version "2.35.1"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c"
- integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==
+rollup@^2.45.2:
+ version "2.45.2"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48"
+ integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==
optionalDependencies:
- fsevents "~2.1.2"
+ fsevents "~2.3.1"
-run-async@^2.0.0, run-async@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
- integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
- dependencies:
- is-promise "^2.1.0"
-
-run-async@^2.4.0:
+run-async@^2.0.0, run-async@^2.2.0, run-async@^2.4.0:
version "2.4.1"
- resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
run-parallel@^1.1.9:
- version "1.1.10"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef"
- integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
-rxjs@^6.4.0:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
- integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
+rxjs@^6.4.0, rxjs@^6.6.0:
+ version "6.6.7"
+ resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz"
+ integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
-rxjs@^6.6.0:
- version "6.6.3"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
- integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
- dependencies:
- tslib "^1.9.0"
-
-safe-buffer@5.1.2, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
- integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-regex@^1.1.0:
version "1.1.0"
@@ -8475,7 +8742,7 @@
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
samsam@1.x, samsam@^1.1.3:
@@ -8484,21 +8751,16 @@
integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
sauce-connect-launcher@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf"
- integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.2.tgz#dfc675a258550809a8eaf457eb9162b943ddbaf0"
+ integrity sha512-wf0coUlidJ7rmeClgVVBh6Kw55/yalZCY/Un5RgjSnTXRAeGqagnTsTYpZaqC4dCtrY4myuYpOAZXCdbO7lHfQ==
dependencies:
adm-zip "~0.4.3"
async "^2.1.2"
- https-proxy-agent "^3.0.0"
+ https-proxy-agent "^5.0.0"
lodash "^4.16.6"
rimraf "^2.5.4"
-sax@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
scoped-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
@@ -8510,22 +8772,21 @@
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
selenium-standalone@^6.7.0:
- version "6.17.0"
- resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.17.0.tgz#0f24b691836205ee9bc3d7a6f207ebcb28170cd9"
- integrity sha512-5PSnDHwMiq+OCiAGlhwQ8BM9xuwFfvBOZ7Tfbw+ifkTnOy0PWbZmI1B9gPGuyGHpbQ/3J3CzIK7BYwrQ7EjtWQ==
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.23.0.tgz#91a7d12b1c8ba077a82b44323445c5882eb20ff1"
+ integrity sha512-6dVLSEvbixd/MRSEmrcRQD8dmABrzNsxRqroKFQY+RVzm1JVPgGHIlo6qJzG6akfjc2V8SadHslE6lN4BFVM3w==
dependencies:
- async "^2.6.2"
- commander "^2.19.0"
- cross-spawn "^6.0.5"
- debug "^4.1.1"
- lodash "^4.17.11"
- minimist "^1.2.0"
- mkdirp "^0.5.1"
+ commander "^2.20.3"
+ cross-spawn "^7.0.3"
+ debug "^4.3.1"
+ got "^11.8.0"
+ lodash.mapvalues "^4.6.0"
+ lodash.merge "^4.6.2"
+ minimist "^1.2.5"
+ mkdirp "^1.0.4"
progress "2.0.3"
- request "2.88.0"
- tar-stream "2.0.0"
- urijs "^1.19.1"
- which "^1.3.1"
+ tar-stream "2.1.4"
+ which "^2.0.2"
yauzl "^2.10.0"
semver-diff@^2.0.0:
@@ -8537,30 +8798,30 @@
semver-diff@^3.1.1:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
+ resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz"
integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
dependencies:
semver "^6.3.0"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.6.0:
- version "5.7.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
- integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
-
-semver@5.6.0, semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
+"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.3.0:
version "5.6.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+ resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+ resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
- integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
+semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
+ version "7.3.5"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
@@ -8622,10 +8883,12 @@
resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
-set-blocking@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+set-getter@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
+ integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=
+ dependencies:
+ to-object-path "^0.3.0"
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
@@ -8652,6 +8915,13 @@
resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+shallow-clone@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+ integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
+ dependencies:
+ kind-of "^6.0.2"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -8661,7 +8931,7 @@
shebang-command@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
@@ -8673,26 +8943,21 @@
shebang-regex@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-shelljs@^0.8.0:
- version "0.8.3"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
- integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+shelljs@^0.8.0, shelljs@^0.8.4:
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
+ integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
-signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
- integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
-
-signal-exit@^3.0.3:
+signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
simple-swizzle@^0.2.2:
@@ -8726,14 +8991,19 @@
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
+slash@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
+ integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
+
slash@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
slice-ansi@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
+ resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz"
integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
dependencies:
ansi-styles "^4.0.0"
@@ -8780,54 +9050,51 @@
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
-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"
- integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+socket.io-client@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
+ integrity sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==
dependencies:
backo2 "1.0.2"
- base64-arraybuffer "0.1.5"
component-bind "1.0.0"
- component-emitter "1.2.1"
- debug "~4.1.0"
- engine.io-client "~3.4.0"
+ component-emitter "~1.3.0"
+ debug "~3.1.0"
+ engine.io-client "~3.5.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"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
socket.io-parser "~3.3.0"
to-array "0.1.4"
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"
- integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
+ integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
dependencies:
- component-emitter "1.2.1"
+ component-emitter "~1.3.0"
debug "~3.1.0"
isarray "2.0.1"
socket.io-parser@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
- integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.1.tgz#b06af838302975837eab2dc980037da24054d64a"
+ integrity sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==
dependencies:
component-emitter "1.2.1"
debug "~4.1.0"
isarray "2.0.1"
socket.io@^2.0.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
- integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2"
+ integrity sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==
dependencies:
debug "~4.1.0"
- engine.io "~3.4.0"
+ engine.io "~3.5.0"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
- socket.io-client "2.3.0"
+ socket.io-client "2.4.0"
socket.io-parser "~3.4.0"
sort-keys-length@^1.0.0:
@@ -8857,13 +9124,13 @@
source-map-support@0.5.9:
version "0.5.9"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f"
+ resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz"
integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
-source-map-support@~0.5.12:
+source-map-support@~0.5.19:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
@@ -8872,9 +9139,9 @@
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"
- integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
@@ -8883,9 +9150,14 @@
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"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+source-map@~0.7.2:
+ version "0.7.3"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
+ integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
+
spawn-sync@^1.0.15:
version "1.0.15"
resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
@@ -8895,38 +9167,30 @@
os-shim "^0.1.2"
spdx-correct@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
- integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz"
+ integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
dependencies:
spdx-expression-parse "^3.0.0"
spdx-license-ids "^3.0.0"
spdx-exceptions@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
- integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz"
+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
-spdx-expression-parse@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
- integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
- dependencies:
- spdx-exceptions "^2.1.0"
- spdx-license-ids "^3.0.0"
-
-spdx-expression-parse@^3.0.1:
+spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1:
version "3.0.1"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz"
integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
- integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
+ version "3.0.7"
+ resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz"
+ integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
spdy-transport@^2.0.18:
version "2.1.1"
@@ -8962,7 +9226,7 @@
sprintf-js@~1.0.2:
version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sshpk@^1.7.0:
@@ -9006,20 +9270,20 @@
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.4.0 < 2", statuses@~1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
- integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
-
-"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+statuses@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+ integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
stream-shift@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
- integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
+ integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
stream@0.0.2:
version "0.0.2"
@@ -9038,7 +9302,7 @@
resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
-string-width@^1.0.1, "string-width@^1.0.2 || 2":
+string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
@@ -9047,7 +9311,7 @@
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
-string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+string-width@^2.0.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
@@ -9057,7 +9321,7 @@
string-width@^3.0.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
@@ -9065,28 +9329,28 @@
strip-ansi "^5.1.0"
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
- integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
+ version "4.2.2"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz"
+ integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
-string.prototype.trimend@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b"
- integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==
+string.prototype.trimend@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz"
+ integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==
dependencies:
- call-bind "^1.0.0"
+ call-bind "^1.0.2"
define-properties "^1.1.3"
-string.prototype.trimstart@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa"
- integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==
+string.prototype.trimstart@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz"
+ integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==
dependencies:
- call-bind "^1.0.0"
+ call-bind "^1.0.2"
define-properties "^1.1.3"
string_decoder@^1.1.1:
@@ -9108,7 +9372,7 @@
dependencies:
safe-buffer "~5.1.0"
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
@@ -9124,14 +9388,14 @@
strip-ansi@^5.1.0:
version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0:
version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz"
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
dependencies:
ansi-regex "^5.0.0"
@@ -9141,6 +9405,13 @@
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
+strip-bom-buf@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
+ integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=
+ dependencies:
+ is-utf8 "^0.2.1"
+
strip-bom-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
@@ -9166,7 +9437,7 @@
strip-bom@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
strip-eof@^1.0.0:
@@ -9176,7 +9447,7 @@
strip-final-newline@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
strip-indent@^1.0.1:
@@ -9193,19 +9464,19 @@
strip-indent@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+ resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz"
integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
dependencies:
min-indent "^1.0.0"
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
strip-json-comments@~2.0.1:
version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
supports-color@^2.0.0:
@@ -9215,15 +9486,15 @@
supports-color@^5.3.0:
version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
@@ -9263,12 +9534,17 @@
wordwrapjs "^3.0.0"
table@^6.0.4:
- version "6.0.4"
- resolved "https://registry.yarnpkg.com/table/-/table-6.0.4.tgz#c523dd182177e926c723eb20e1b341238188aa0d"
- integrity sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==
+ version "6.0.9"
+ resolved "https://registry.npmjs.org/table/-/table-6.0.9.tgz"
+ integrity sha512-F3cLs9a3hL1Z7N4+EkSscsel3z55XT950AvB05bwayrNg5T1/gykXtigioTAjbltvbMSJvvhFCbnf6mX+ntnJQ==
dependencies:
- ajv "^6.12.4"
- lodash "^4.17.20"
+ ajv "^8.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ lodash.clonedeep "^4.5.0"
+ lodash.flatten "^4.4.0"
+ lodash.truncate "^4.4.2"
slice-ansi "^4.0.0"
string-width "^4.2.0"
@@ -9282,12 +9558,12 @@
pump "^1.0.0"
tar-stream "^1.1.2"
-tar-stream@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
- integrity sha512-n2vtsWshZOVr/SY4KtslPoUlyNh06I2SGgAOCZmquCEjlbV/LjY2CY80rDtdQRHFOYXNlgBDo6Fr3ww2CWPOtA==
+tar-stream@2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa"
+ integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==
dependencies:
- bl "^2.2.0"
+ bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
@@ -9307,44 +9583,23 @@
xtend "^4.0.0"
tar-stream@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
- integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+ integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
dependencies:
- bl "^3.0.0"
+ bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
-tar@^4:
- version "4.4.8"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
- integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
- dependencies:
- chownr "^1.1.1"
- fs-minipass "^1.2.5"
- minipass "^2.3.4"
- minizlib "^1.1.1"
- mkdirp "^0.5.0"
- safe-buffer "^5.1.2"
- yallist "^3.0.2"
-
-temp@^0.8.1:
+temp@^0.8.1, temp@^0.8.3:
version "0.8.4"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
dependencies:
rimraf "~2.6.2"
-temp@^0.8.3:
- version "0.8.3"
- resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59"
- integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=
- dependencies:
- os-tmpdir "^1.0.0"
- rimraf "~2.2.6"
-
term-size@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -9352,29 +9607,24 @@
dependencies:
execa "^0.7.0"
-term-size@^2.1.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
- integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
-
ternary-stream@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269"
- integrity sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.1.1.tgz#4ad64b98668d796a085af2c493885a435a8a8bfc"
+ integrity sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==
dependencies:
duplexify "^3.5.0"
fork-stream "^0.0.4"
merge-stream "^1.0.0"
through2 "^2.0.1"
-terser@^4.8.0:
- version "4.8.0"
- resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
- integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
+terser@^5.6.1:
+ version "5.6.1"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.1.tgz#a48eeac5300c0a09b36854bf90d9c26fb201973c"
+ integrity sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw==
dependencies:
commander "^2.20.0"
- source-map "~0.6.1"
- source-map-support "~0.5.12"
+ source-map "~0.7.2"
+ source-map-support "~0.5.19"
text-encoding@0.6.4:
version "0.6.4"
@@ -9388,13 +9638,13 @@
text-table@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-textextensions@^2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.4.0.tgz#6a143a985464384cc2cff11aea448cd5b018e72b"
- integrity sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==
+textextensions@^2.5.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4"
+ integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==
thenify-all@^1.0.0:
version "1.6.0"
@@ -9404,9 +9654,9 @@
thenify ">= 3.1.0 < 4"
"thenify@>= 3.1.0 < 4":
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
- integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
dependencies:
any-promise "^1.0.0"
@@ -9442,16 +9692,17 @@
readable-stream "~2.3.6"
xtend "~4.0.1"
-through2@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
- integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
+through2@^3.0.0, through2@^3.0.1, through2@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4"
+ integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==
dependencies:
+ inherits "^2.0.4"
readable-stream "2 || 3"
-through@^2.3.6:
+"through@>=2.2.7 <3", through@^2.3.6:
version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timed-out@^3.0.0:
@@ -9473,7 +9724,7 @@
tmp@^0.0.33:
version "0.0.33"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
dependencies:
os-tmpdir "~1.0.2"
@@ -9514,7 +9765,7 @@
to-readable-stream@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
+ resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz"
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
to-regex-range@^2.1.0:
@@ -9527,7 +9778,7 @@
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"
+ resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
@@ -9555,6 +9806,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"
@@ -9569,7 +9828,7 @@
trim-newlines@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30"
+ resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz"
integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==
trim-right@^1.0.1:
@@ -9584,7 +9843,7 @@
tsconfig-paths@^3.9.0:
version "3.9.0"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
+ resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz"
integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
dependencies:
"@types/json5" "^0.0.29"
@@ -9592,27 +9851,22 @@
minimist "^1.2.0"
strip-bom "^3.0.0"
-tslib@^1.8.1:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
- integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
-
-tslib@^1.9.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
- integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+tslib@^1.8.1, tslib@^1.9.0:
+ version "1.14.1"
+ resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tsutils@2.27.2:
version "2.27.2"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
+ resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.27.2.tgz"
integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==
dependencies:
tslib "^1.8.1"
tsutils@^3.17.1:
- version "3.17.1"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
- integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
+ version "3.21.0"
+ resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
+ integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"
@@ -9630,7 +9884,7 @@
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
@@ -9640,24 +9894,29 @@
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-type-fest@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
- integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
-
type-fest@^0.18.0:
version "0.18.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz"
integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
type-fest@^0.6.0:
version "0.6.0"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz"
integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
type-fest@^0.8.1:
version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
@@ -9670,7 +9929,7 @@
typedarray-to-buffer@^3.1.5:
version "3.1.5"
- resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
dependencies:
is-typedarray "^1.0.0"
@@ -9680,10 +9939,10 @@
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389"
- integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==
+typescript@4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.4.tgz#f058636e2f4f83f94ddaae07b20fd5e14598432f"
+ integrity sha512-+Uru0t8qIRgjuCpiSPpfGuhHecMllk5Zsazj5LZvVsEStEjmIRRBZe+jHjGQvsgS7M1wONy2PQXd67EMyV6acg==
typical@^2.6.1:
version "2.6.1"
@@ -9696,9 +9955,9 @@
integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
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"
- integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+ version "0.7.28"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
+ integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
uglify-js@3.4.x:
version "3.4.10"
@@ -9708,10 +9967,20 @@
commander "~2.19.0"
source-map "~0.6.1"
+unbox-primitive@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz"
+ integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
+ dependencies:
+ function-bind "^1.1.1"
+ has-bigints "^1.0.1"
+ has-symbols "^1.0.2"
+ which-boxed-primitive "^1.0.2"
+
underscore@^1.8.3:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
- integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.0.tgz#3ccdcbb824230fc6bf234ad0ddcd83dff4eafe5f"
+ integrity sha512-sCs4H3pCytsb5K7i072FAEC9YlSYFIbosvM0tAKAlpSSUgD7yC1iXSEGdl5XrDKQ1YUB+p/HDzYrSG2H2Vl36g==
underscore@~1.6.0:
version "1.6.0"
@@ -9731,15 +10000,15 @@
unicode-canonical-property-names-ecmascript "^1.0.4"
unicode-property-aliases-ecmascript "^1.0.4"
-unicode-match-property-value-ecmascript@^1.1.0:
- version "1.1.0"
- 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"
- integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
+ integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
union-value@^1.0.0:
version "1.0.1"
@@ -9768,17 +10037,22 @@
unique-string@^2.0.0:
version "2.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
+ resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz"
integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
dependencies:
crypto-random-string "^2.0.0"
-universal-user-agent@^2.0.0, universal-user-agent@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.1.0.tgz#5abfbcc036a1ba490cb941f8fd68c46d3669e8e4"
- integrity sha512-8itiX7G05Tu3mGDTdNY2fB4KJ8MgZLS54RdG6PkkfwMAavrXu1mV/lls/GABx9O3Rw4PnTtasxrvbMQoBYY92Q==
+universal-user-agent@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557"
+ integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==
dependencies:
- os-name "^3.0.0"
+ os-name "^3.1.0"
+
+universal-user-agent@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
+ integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
@@ -9846,22 +10120,22 @@
xdg-basedir "^3.0.0"
update-notifier@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.0.1.tgz#1f92d45fb1f70b9e33880a72dd262bc12d22c20d"
- integrity sha512-BuVpRdlwxeIOvmc32AGYvO1KVdPlsmqSh8KDDBxS6kDE5VR7R8OMP1d8MdhaVBvxl4H3551k9akXr0Y1iIB2Wg==
+ version "5.1.0"
+ resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz"
+ integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==
dependencies:
- boxen "^4.2.0"
+ boxen "^5.0.0"
chalk "^4.1.0"
configstore "^5.0.1"
has-yarn "^2.1.0"
import-lazy "^2.1.0"
is-ci "^2.0.0"
- is-installed-globally "^0.3.2"
+ is-installed-globally "^0.4.0"
is-npm "^5.0.0"
is-yarn-global "^0.3.0"
latest-version "^5.1.0"
pupa "^2.1.1"
- semver "^7.3.2"
+ semver "^7.3.4"
semver-diff "^3.1.1"
xdg-basedir "^4.0.0"
@@ -9871,21 +10145,16 @@
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.1"
+ resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
urijs@^1.16.1:
- version "1.19.1"
- resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.1.tgz#5b0ff530c0cbde8386f6342235ba5ca6e995d25a"
- integrity sha512-xVrGVi94ueCJNrBSTjWqjvtgvl3cyOTThp2zaMaFNGp3F542TR6sM3f2o8RqZl+AwteClSVmoCyt0ka4RjQOQg==
-
-urijs@^1.19.1:
- version "1.19.2"
- resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
- integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
+ version "1.19.6"
+ resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.6.tgz#51f8cb17ca16faefb20b9a31ac60f84aa2b7c870"
+ integrity sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw==
urix@^0.1.0:
version "0.1.0"
@@ -9901,16 +10170,11 @@
url-parse-lax@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
+ resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
dependencies:
prepend-http "^2.0.0"
-url-template@^2.0.8:
- version "2.0.8"
- resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
- integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE=
-
url-to-options@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
@@ -9937,14 +10201,14 @@
integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=
uuid@^3.2.1, uuid@^3.3.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
- integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+ integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
v8-compile-cache@^2.0.3:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
- integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
+ integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
vali-date@^1.0.0:
version "1.0.0"
@@ -9962,7 +10226,7 @@
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"
+ resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
dependencies:
spdx-correct "^3.0.0"
@@ -9987,17 +10251,16 @@
core-util-is "1.0.2"
extsprintf "^1.2.0"
-vinyl-file@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a"
- integrity sha1-p+v1/779obfRjRQPyweyI++2dRo=
+vinyl-file@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
+ integrity sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=
dependencies:
graceful-fs "^4.1.2"
pify "^2.3.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
+ strip-bom-buf "^1.0.0"
strip-bom-stream "^2.0.0"
- vinyl "^1.1.0"
+ vinyl "^2.0.1"
vinyl-fs@^2.4.3, vinyl-fs@^2.4.4:
version "2.4.4"
@@ -10022,7 +10285,7 @@
vali-date "^1.0.0"
vinyl "^1.0.0"
-vinyl@^1.0.0, vinyl@^1.1.0, vinyl@^1.1.1, vinyl@^1.2.0:
+vinyl@^1.0.0, vinyl@^1.1.1, vinyl@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
@@ -10031,10 +10294,10 @@
clone-stats "^0.0.1"
replace-ext "0.0.1"
-vinyl@^2.0.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
- integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==
+vinyl@^2.0.1, vinyl@^2.2.0, vinyl@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
+ integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
dependencies:
clone "^2.1.1"
clone-buffer "^1.0.0"
@@ -10090,9 +10353,9 @@
uuid "^3.2.1"
wd@^1.2.0:
- version "1.12.0"
- resolved "https://registry.yarnpkg.com/wd/-/wd-1.12.0.tgz#763ce9ebcaa854ab8e05d0a660f24da839674329"
- integrity sha512-P8fOXV+FAxR7Pdto4sQ982ud6xUJHzxfY/JYH+NfBJ2EYJhGeO7fLXiVKosZK3YlZK7EQfPmUVqkbEzNlGTGgQ==
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/wd/-/wd-1.14.0.tgz#1fe6450b5baef37caa135e7755292c6998ca8a90"
+ integrity sha512-X7ZfGHHYlQ5zYpRlgP16LUsvYti+Al/6fz3T/ClVyivVCpCZQpESTDdz6zbK910O5OIvujO23Ym2DBBo3XsQlA==
dependencies:
archiver "^3.0.0"
async "^2.0.0"
@@ -10151,27 +10414,31 @@
tr46 "^1.0.1"
webidl-conversions "^4.0.2"
-which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+which-boxed-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
+ integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+ dependencies:
+ is-bigint "^1.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ is-symbol "^1.0.3"
+
+which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
-which@^2.0.1:
+which@^2.0.1, which@^2.0.2:
version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
-wide-align@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
- integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
- dependencies:
- string-width "^1.0.2 || 2"
-
widest-line@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
@@ -10188,45 +10455,45 @@
widest-line@^3.1.0:
version "3.1.0"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
+ resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz"
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
dependencies:
string-width "^4.0.0"
windows-release@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
- integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999"
+ integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==
dependencies:
execa "^1.0.0"
-winston-transport@^4.2.0, winston-transport@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66"
- integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==
+winston-transport@^4.2.0, winston-transport@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59"
+ integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==
dependencies:
- readable-stream "^2.3.6"
+ readable-stream "^2.3.7"
triple-beam "^1.2.0"
winston@^3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"
- integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"
+ integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==
dependencies:
- async "^2.6.1"
- diagnostics "^1.1.1"
- is-stream "^1.1.0"
- logform "^2.1.1"
- one-time "0.0.4"
- readable-stream "^3.1.1"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.1.0"
+ is-stream "^2.0.0"
+ logform "^2.2.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
stack-trace "0.0.x"
triple-beam "^1.3.0"
- winston-transport "^4.3.0"
+ winston-transport "^4.4.0"
with-open-file@^0.1.6:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.6.tgz#0bc178ecab75f6baac8ae11c85e07445d690ea50"
- integrity sha512-SQS05JekbtwQSgCYlBsZn/+m2gpn4zWsqpCYIrCHva0+ojXcnmUEPsBN6Ipoz3vmY/81k5PvYEWSxER2g4BTqA==
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.7.tgz#e2de8d974e8a8ae6e58886be4fe8e7465b58a729"
+ integrity sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==
dependencies:
p-finally "^1.0.0"
p-try "^2.1.0"
@@ -10234,10 +10501,10 @@
word-wrap@^1.2.3:
version "1.2.3"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+ resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
-wordwrap@~0.0.2:
+wordwrap@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
@@ -10250,9 +10517,18 @@
reduce-flatten "^1.0.1"
typical "^2.6.1"
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrappy@1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
write-file-atomic@^1.1.2:
@@ -10275,7 +10551,7 @@
write-file-atomic@^3.0.0, write-file-atomic@^3.0.3:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+ resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz"
integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
dependencies:
imurmurhash "^0.1.4"
@@ -10283,17 +10559,10 @@
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
-ws@^7.1.2:
- version "7.2.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
- integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
-
-ws@~6.1.0:
- version "6.1.4"
- resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
- integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
- dependencies:
- async-limiter "~1.0.0"
+ws@~7.4.2:
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
+ integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
xdg-basedir@^2.0.0:
version "2.0.0"
@@ -10309,7 +10578,7 @@
xdg-basedir@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
+ resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
xmlbuilder@8.2.2:
@@ -10337,20 +10606,15 @@
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-yallist@^3.0.0, yallist@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
- integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
-
yallist@^4.0.0:
version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yargs-parser@^20.2.3:
- version "20.2.4"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
- integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
+ version "20.2.7"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz"
+ integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
yauzl@^2.10.0:
version "2.10.0"
@@ -10383,26 +10647,30 @@
text-table "^0.2.0"
untildify "^2.0.0"
-yeoman-environment@^2.0.5:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.4.0.tgz#4829445dc1306b02d9f5f7027cd224bf77a8224d"
- integrity sha512-SsvoL0RNAFIX69eFxkUhwKUN2hG1UwUjxrcP+T2ytwdhqC/kHdnFOH2SXdtSN1Ju4aO4xuimmzfRoheYY88RuA==
+yeoman-environment@^2.0.5, yeoman-environment@^2.9.5:
+ version "2.10.3"
+ resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.10.3.tgz#9d8f42b77317414434cc0e51fb006a4bdd54688e"
+ integrity sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==
dependencies:
chalk "^2.4.1"
- cross-spawn "^6.0.5"
debug "^3.1.0"
diff "^3.5.0"
escape-string-regexp "^1.0.2"
+ execa "^4.0.0"
globby "^8.0.1"
- grouped-queue "^0.3.3"
- inquirer "^6.0.0"
+ grouped-queue "^1.1.0"
+ inquirer "^7.1.0"
is-scoped "^1.0.0"
lodash "^4.17.10"
log-symbols "^2.2.0"
mem-fs "^1.1.0"
+ mem-fs-editor "^6.0.0"
+ npm-api "^1.0.0"
+ semver "^7.1.3"
strip-ansi "^4.0.0"
text-table "^0.2.0"
untildify "^3.0.3"
+ yeoman-generator "^4.8.2"
yeoman-generator@^3.1.1:
version "3.2.0"
@@ -10435,6 +10703,40 @@
through2 "^3.0.0"
yeoman-environment "^2.0.5"
+yeoman-generator@^4.8.2:
+ version "4.13.0"
+ resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-4.13.0.tgz#a6caeed8491fceea1f84f53e31795f25888b4672"
+ integrity sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==
+ dependencies:
+ async "^2.6.2"
+ chalk "^2.4.2"
+ cli-table "^0.3.1"
+ cross-spawn "^6.0.5"
+ dargs "^6.1.0"
+ dateformat "^3.0.3"
+ debug "^4.1.1"
+ diff "^4.0.1"
+ error "^7.0.2"
+ find-up "^3.0.0"
+ github-username "^3.0.0"
+ istextorbinary "^2.5.1"
+ lodash "^4.17.11"
+ make-dir "^3.0.0"
+ mem-fs-editor "^7.0.1"
+ minimist "^1.2.5"
+ pretty-bytes "^5.2.0"
+ read-chunk "^3.2.0"
+ read-pkg-up "^5.0.0"
+ rimraf "^2.6.3"
+ run-async "^2.0.0"
+ semver "^7.2.1"
+ shelljs "^0.8.4"
+ text-table "^0.2.0"
+ through2 "^3.0.1"
+ optionalDependencies:
+ grouped-queue "^1.1.0"
+ yeoman-environment "^2.9.5"
+
zip-stream@^2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"