Merge "UserPreferencesConverter: use ProtoConverter interface"
diff --git a/java/com/google/gerrit/server/account/AccountLoader.java b/java/com/google/gerrit/server/account/AccountLoader.java
index c260401..42687987 100644
--- a/java/com/google/gerrit/server/account/AccountLoader.java
+++ b/java/com/google/gerrit/server/account/AccountLoader.java
@@ -21,6 +21,9 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.server.account.AccountDirectory.FillOptions;
+import com.google.gerrit.server.logging.Metadata;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
@@ -90,7 +93,9 @@
}
public void fill() throws PermissionBackendException {
- directory.fillAccountInfo(Iterables.concat(created.values(), provided), options);
+ try (TraceTimer timer = TraceContext.newTimer("Fill accounts", Metadata.empty())) {
+ directory.fillAccountInfo(Iterables.concat(created.values(), provided), options);
+ }
}
public void fill(Collection<? extends AccountInfo> infos) throws PermissionBackendException {
diff --git a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
index db030f9..a05baf5 100644
--- a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
+++ b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
@@ -19,6 +19,9 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.logging.Metadata;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Scopes;
@@ -63,41 +66,43 @@
@Override
public boolean isServiceUser(Account.Id user) {
- Optional<InternalGroup> maybeGroup = groupCache.get(AccountGroup.nameKey(SERVICE_USERS));
- if (!maybeGroup.isPresent()) {
+ try (TraceTimer timer = TraceContext.newTimer("isServiceUser", Metadata.empty())) {
+ Optional<InternalGroup> maybeGroup = groupCache.get(AccountGroup.nameKey(SERVICE_USERS));
+ if (!maybeGroup.isPresent()) {
+ return false;
+ }
+ List<AccountGroup.UUID> toTraverse = new ArrayList<>();
+ toTraverse.add(maybeGroup.get().getGroupUUID());
+ Set<AccountGroup.UUID> seen = new HashSet<>();
+ while (!toTraverse.isEmpty()) {
+ InternalGroup currentGroup =
+ groupCache
+ .get(toTraverse.remove(0))
+ .orElseThrow(() -> new IllegalStateException("invalid subgroup"));
+ if (seen.contains(currentGroup.getGroupUUID())) {
+ logger.atFine().log(
+ "Skipping %s because it's a cyclic subgroup", currentGroup.getGroupUUID());
+ continue;
+ }
+ seen.add(currentGroup.getGroupUUID());
+ if (currentGroup.getMembers().contains(user)) {
+ // The user is a member of the 'Service Users' group or a subgroup.
+ return true;
+ }
+ boolean hasExternalSubgroup =
+ currentGroup.getSubgroups().stream().anyMatch(g -> !internalGroupBackend.handles(g));
+ if (hasExternalSubgroup) {
+ // 'Service Users or a subgroup of Service User' contains an external subgroup, so we have
+ // to default to the more expensive evaluation of getting all of the user's group
+ // memberships.
+ return identifiedUserFactory
+ .create(user)
+ .getEffectiveGroups()
+ .contains(maybeGroup.get().getGroupUUID());
+ }
+ toTraverse.addAll(currentGroup.getSubgroups());
+ }
return false;
}
- List<AccountGroup.UUID> toTraverse = new ArrayList<>();
- toTraverse.add(maybeGroup.get().getGroupUUID());
- Set<AccountGroup.UUID> seen = new HashSet<>();
- while (!toTraverse.isEmpty()) {
- InternalGroup currentGroup =
- groupCache
- .get(toTraverse.remove(0))
- .orElseThrow(() -> new IllegalStateException("invalid subgroup"));
- if (seen.contains(currentGroup.getGroupUUID())) {
- logger.atFine().log(
- "Skipping %s because it's a cyclic subgroup", currentGroup.getGroupUUID());
- continue;
- }
- seen.add(currentGroup.getGroupUUID());
- if (currentGroup.getMembers().contains(user)) {
- // The user is a member of the 'Service Users' group or a subgroup.
- return true;
- }
- boolean hasExternalSubgroup =
- currentGroup.getSubgroups().stream().anyMatch(g -> !internalGroupBackend.handles(g));
- if (hasExternalSubgroup) {
- // 'Service Users or a subgroup of Service User' contains an external subgroup, so we have
- // to default to the more expensive evaluation of getting all of the user's group
- // memberships.
- return identifiedUserFactory
- .create(user)
- .getEffectiveGroups()
- .contains(maybeGroup.get().getGroupUUID());
- }
- toTraverse.addAll(currentGroup.getSubgroups());
- }
- return false;
}
}
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index 03728a0..d557273 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -437,13 +437,16 @@
if (!isElementTarget(rootTarget)) return false;
const tagName = rootTarget.tagName;
const type = rootTarget.getAttribute('type');
+ const editable = rootTarget.hasAttribute('contenteditable');
if (
+ editable ||
// Suppress shortcuts on <input> and <textarea>, but not on
// checkboxes, because we want to enable workflows like 'click
// mark-reviewed and then press ] to go to the next file'.
(tagName === 'INPUT' && type !== 'checkbox') ||
tagName === 'TEXTAREA' ||
+ tagName === 'GR-TEXTAREA' ||
(e.key === 'Enter' &&
(tagName === 'A' ||
tagName === 'BUTTON' ||
diff --git a/polygerrit-ui/app/utils/dom-util_test.ts b/polygerrit-ui/app/utils/dom-util_test.ts
index fe185be..7deae3d 100644
--- a/polygerrit-ui/app/utils/dom-util_test.ts
+++ b/polygerrit-ui/app/utils/dom-util_test.ts
@@ -309,6 +309,14 @@
});
});
+ test('suppress shortcut event from <div contenteditable>', async () => {
+ const el = document.createElement('div');
+ el.setAttribute('contenteditable', '');
+ await keyEventOn(el, e => {
+ assert.isTrue(shouldSuppress(e));
+ });
+ });
+
test('suppress shortcut event from <input>', async () => {
await keyEventOn(document.createElement('input'), e => {
assert.isTrue(shouldSuppress(e));
@@ -321,6 +329,12 @@
});
});
+ test('suppress shortcut event from <gr-textarea>', async () => {
+ await keyEventOn(document.createElement('gr-textarea'), e => {
+ assert.isTrue(shouldSuppress(e));
+ });
+ });
+
test('do not suppress shortcut event from checkbox <input>', async () => {
const inputEl = document.createElement('input');
inputEl.setAttribute('type', 'checkbox');