Merge changes Iea805a88,I0a94509e

* changes:
  Refactor usage of thread elements in gr-diff
  Avoid 'comment thread without side' error
diff --git a/java/com/google/gerrit/server/config/ConfigUtil.java b/java/com/google/gerrit/server/config/ConfigUtil.java
index 43c05e0..27ded63 100644
--- a/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -16,6 +16,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.flogger.FluentLogger;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Modifier;
@@ -30,6 +31,8 @@
 import org.eclipse.jgit.lib.Config;
 
 public class ConfigUtil {
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
   @SuppressWarnings("unchecked")
   private static <T> T[] allValuesOf(T defaultValue) {
     try {
@@ -138,7 +141,12 @@
     } else {
       for (String string : values) {
         if (string != null) {
-          list.add(getEnum(section, subsection, setting, string, all));
+          try {
+            list.add(getEnum(section, subsection, setting, string, all));
+          } catch (IllegalArgumentException ex) {
+            // It's better to ignore a wrongly configured enum, rather than fail to load Gerrit.
+            logger.atWarning().log(ex.getMessage());
+          }
         }
       }
     }
diff --git a/plugins/gitiles b/plugins/gitiles
index e929d29..a33c8b8 160000
--- a/plugins/gitiles
+++ b/plugins/gitiles
@@ -1 +1 @@
-Subproject commit e929d29973ac732a096d1920b8060eafdd04316e
+Subproject commit a33c8b8d61b778f8ca84196b1a7cc1fd4fe24946
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index 9834ddc..c8de2eb 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -272,6 +272,7 @@
         }],
         // The following rules is required to match internal google rules
         "@typescript-eslint/restrict-plus-operands": "error",
+        "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
         // https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-unsupported-features/node-builtins.md
         "node/no-unsupported-features/node-builtins": "off",
         // Disable no-invalid-this for ts files, because it incorrectly reports
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 caa0521..c4ed683 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
@@ -348,6 +348,7 @@
     // If not, it sets target='_blank' on the menu item. The server
     // makes assumptions that work for the GWT UI, but not PolyGerrit,
     // so we'll just disable it altogether for now.
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
     const {target, ...headerLink} = {...linkObj};
 
     // Normalize all urls to PolyGerrit style.
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.ts
index eb11588..11d3ce3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.ts
@@ -83,8 +83,9 @@
 
   const numHidden = hiddenEnd - hiddenStart;
 
-  // Only collapse if there is more than 1 line to be hidden.
-  if (numHidden > 1) {
+  // Showing a context control row for less than 4 lines does not make much,
+  // because then that row would consume as much space as the collapsed code.
+  if (numHidden > 3) {
     if (hiddenStart) {
       [before, hidden] = _splitCommonGroups(hidden, hiddenStart);
     }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.js
index 3423834..8182941 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.js
@@ -122,17 +122,19 @@
           new GrDiffLine(GrDiffLineType.ADD, 0, 11),
           new GrDiffLine(GrDiffLineType.REMOVE, 10),
           new GrDiffLine(GrDiffLineType.ADD, 0, 12),
+          new GrDiffLine(GrDiffLineType.REMOVE, 11),
+          new GrDiffLine(GrDiffLineType.ADD, 0, 13),
         ]),
         new GrDiffGroup(GrDiffGroupType.BOTH, [
-          new GrDiffLine(GrDiffLineType.BOTH, 11, 13),
           new GrDiffLine(GrDiffLineType.BOTH, 12, 14),
           new GrDiffLine(GrDiffLineType.BOTH, 13, 15),
+          new GrDiffLine(GrDiffLineType.BOTH, 14, 16),
         ]),
       ];
     });
 
     test('hides hidden groups in context control', () => {
-      const collapsedGroups = hideInContextControl(groups, 3, 6);
+      const collapsedGroups = hideInContextControl(groups, 3, 7);
       assert.equal(collapsedGroups.length, 3);
 
       assert.equal(collapsedGroups[0], groups[0]);
@@ -145,7 +147,7 @@
     });
 
     test('splits partially hidden groups', () => {
-      const collapsedGroups = hideInContextControl(groups, 4, 7);
+      const collapsedGroups = hideInContextControl(groups, 4, 8);
       assert.equal(collapsedGroups.length, 4);
       assert.equal(collapsedGroups[0], groups[0]);
 
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 fac5f45..7a27b03 100644
--- a/polygerrit-ui/app/elements/gr-app-global-var-init.ts
+++ b/polygerrit-ui/app/elements/gr-app-global-var-init.ts
@@ -22,61 +22,13 @@
  * expose these variables until plugins switch to direct import from polygerrit.
  */
 
-import {
-  getAccountDisplayName,
-  getDisplayName,
-  getGroupDisplayName,
-  getUserName,
-} from '../utils/display-name-util';
 import {GrAnnotation} from './diff/gr-diff-highlight/gr-annotation';
-import {GrAttributeHelper} from './plugins/gr-attribute-helper/gr-attribute-helper';
 import {GrDiffLine, GrDiffLineType} from './diff/gr-diff/gr-diff-line';
 import {GrDiffGroup, GrDiffGroupType} from './diff/gr-diff/gr-diff-group';
-import {GrDiffBuilder} from './diff/gr-diff-builder/gr-diff-builder';
-import {GrDiffBuilderSideBySide} from './diff/gr-diff-builder/gr-diff-builder-side-by-side';
-import {GrDiffBuilderImage} from './diff/gr-diff-builder/gr-diff-builder-image';
-import {GrDiffBuilderUnified} from './diff/gr-diff-builder/gr-diff-builder-unified';
-import {GrDiffBuilderBinary} from './diff/gr-diff-builder/gr-diff-builder-binary';
-import {GrChangeActionsInterface} from './shared/gr-js-api-interface/gr-change-actions-js-api';
-import {GrChangeReplyInterface} from './shared/gr-js-api-interface/gr-change-reply-js-api';
-import {GrEditConstants} from './edit/gr-edit-constants';
-import {
-  GrDomHooksManager,
-  GrDomHook,
-} from './plugins/gr-dom-hooks/gr-dom-hooks';
-import {GrEtagDecorator} from './shared/gr-rest-api-interface/gr-etag-decorator';
-import {GrThemeApi} from './plugins/gr-theme-api/gr-theme-api';
-import {
-  SiteBasedCache,
-  FetchPromisesCache,
-  GrRestApiHelper,
-} from './shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
-import {GrLinkTextParser} from './shared/gr-linked-text/link-text-parser';
-import {
-  getPluginEndpoints,
-  GrPluginEndpoints,
-} from './shared/gr-js-api-interface/gr-plugin-endpoints';
-import {GrReviewerUpdatesParser} from './shared/gr-rest-api-interface/gr-reviewer-updates-parser';
-import {GrPopupInterface} from './plugins/gr-popup-interface/gr-popup-interface';
-import {GrCountStringFormatter} from './shared/gr-count-string-formatter/gr-count-string-formatter';
-import {
-  GrReviewerSuggestionsProvider,
-  SUGGESTIONS_PROVIDERS_USERS_TYPES,
-} from '../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider';
+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 {GrAdminApi} from './plugins/gr-admin-api/gr-admin-api';
-import {GrAnnotationActionsContext} from './shared/gr-js-api-interface/gr-annotation-actions-context';
-import {GrAnnotationActionsInterface} from './shared/gr-js-api-interface/gr-annotation-actions-js-api';
-import {GrChangeMetadataApi} from './plugins/gr-change-metadata-api/gr-change-metadata-api';
-import {GrEmailSuggestionsProvider} from '../scripts/gr-email-suggestions-provider/gr-email-suggestions-provider';
-import {GrGroupSuggestionsProvider} from '../scripts/gr-group-suggestions-provider/gr-group-suggestions-provider';
-import {GrEventHelper} from './plugins/gr-event-helper/gr-event-helper';
-import {GrPluginRestApi} from './shared/gr-js-api-interface/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 {
   getPluginLoader,
   PluginLoader,
@@ -92,60 +44,18 @@
 import {getBaseUrl} from '../utils/url-util';
 import {GerritNav} from './core/gr-navigation/gr-navigation';
 import {getRootElement} from '../scripts/rootElement';
-import {rangesEqual} from './diff/gr-diff/gr-diff-utils';
 import {RevisionInfo} from './shared/revision-info/revision-info';
-import {CoverageType} from '../types/types';
-import {_setHiddenScroll, getHiddenScroll} from '../scripts/hiddenscroll';
 
 export function initGlobalVariables() {
-  window.GrDisplayNameUtils = {
-    getUserName,
-    getDisplayName,
-    getAccountDisplayName,
-    getGroupDisplayName,
-  };
   window.GrAnnotation = GrAnnotation;
-  window.GrAttributeHelper = GrAttributeHelper;
   window.GrDiffLine = GrDiffLine;
   window.GrDiffLineType = GrDiffLineType;
   window.GrDiffGroup = GrDiffGroup;
   window.GrDiffGroupType = GrDiffGroupType;
-  window.GrDiffBuilder = GrDiffBuilder;
-  window.GrDiffBuilderSideBySide = GrDiffBuilderSideBySide;
-  window.GrDiffBuilderImage = GrDiffBuilderImage;
-  window.GrDiffBuilderUnified = GrDiffBuilderUnified;
-  window.GrDiffBuilderBinary = GrDiffBuilderBinary;
-  window.GrChangeActionsInterface = GrChangeActionsInterface;
-  window.GrChangeReplyInterface = GrChangeReplyInterface;
-  window.GrEditConstants = GrEditConstants;
-  window.GrDomHooksManager = GrDomHooksManager;
-  window.GrDomHook = GrDomHook;
-  window.GrEtagDecorator = GrEtagDecorator;
-  window.GrThemeApi = GrThemeApi;
-  window.SiteBasedCache = SiteBasedCache;
-  window.FetchPromisesCache = FetchPromisesCache;
-  window.GrRestApiHelper = GrRestApiHelper;
-  window.GrLinkTextParser = GrLinkTextParser;
-  window.GrPluginEndpoints = GrPluginEndpoints;
-  window.GrReviewerUpdatesParser = GrReviewerUpdatesParser;
-  window.GrPopupInterface = GrPopupInterface;
-  window.GrCountStringFormatter = GrCountStringFormatter;
-  window.GrReviewerSuggestionsProvider = GrReviewerSuggestionsProvider;
   window.util = util;
   window.page = page;
   window.Auth = appContext.authService;
   window.EventEmitter = appContext.eventEmitter;
-  window.GrAdminApi = GrAdminApi;
-  window.GrAnnotationActionsContext = GrAnnotationActionsContext;
-  window.GrAnnotationActionsInterface = GrAnnotationActionsInterface;
-  window.GrChangeMetadataApi = GrChangeMetadataApi;
-  window.GrEmailSuggestionsProvider = GrEmailSuggestionsProvider;
-  window.GrGroupSuggestionsProvider = GrGroupSuggestionsProvider;
-  window.GrEventHelper = GrEventHelper;
-  window.GrPluginRestApi = GrPluginRestApi;
-  window.GrRepoApi = GrRepoApi;
-  window.GrSettingsApi = GrSettingsApi;
-  window.GrStylesApi = GrStylesApi;
   window.PluginLoader = PluginLoader;
   window.GrPluginActionContext = GrPluginActionContext;
 
@@ -167,14 +77,5 @@
   // TODO: should define as a getter
   window.Gerrit._endpoints = getPluginEndpoints();
 
-  // TODO(TS): seems not used, probably just remove
-  window.Gerrit.slotToContent = (slot: any) => slot;
-  window.Gerrit.rangesEqual = rangesEqual;
-  window.Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES = SUGGESTIONS_PROVIDERS_USERS_TYPES;
   window.Gerrit.RevisionInfo = RevisionInfo;
-  window.Gerrit.CoverageType = CoverageType;
-  Object.defineProperty(window.Gerrit, 'hiddenscroll', {
-    get: getHiddenScroll,
-    set: _setHiddenScroll,
-  });
 }
diff --git a/polygerrit-ui/app/types/globals.ts b/polygerrit-ui/app/types/globals.ts
index d208d4f..628cee4 100644
--- a/polygerrit-ui/app/types/globals.ts
+++ b/polygerrit-ui/app/types/globals.ts
@@ -36,12 +36,7 @@
       Auth?: unknown;
       _pluginLoader?: unknown;
       _endpoints?: unknown;
-      slotToContent?: unknown;
-      rangesEqual?: unknown;
-      SUGGESTIONS_PROVIDERS_USERS_TYPES?: unknown;
       RevisionInfo?: unknown;
-      CoverageType?: unknown;
-      hiddenscroll?: unknown;
       flushPreinstalls?: () => void;
     };
     // TODO(TS): define polymer type
@@ -69,49 +64,16 @@
     // TODO(TS): should clean up those and removing them may break certain plugin behaviors
     // TODO(TS): as @brohlfs suggested, to avoid importing anything from elements/ to types/
     // use any for them for now
-    GrDisplayNameUtils: unknown;
     GrAnnotation: unknown;
-    GrAttributeHelper: unknown;
     GrDiffLine: unknown;
     GrDiffLineType: unknown;
     GrDiffGroup: unknown;
     GrDiffGroupType: unknown;
-    GrDiffBuilder: unknown;
-    GrDiffBuilderSideBySide: unknown;
-    GrDiffBuilderImage: unknown;
-    GrDiffBuilderUnified: unknown;
-    GrDiffBuilderBinary: unknown;
-    GrChangeActionsInterface: unknown;
-    GrChangeReplyInterface: unknown;
-    GrEditConstants: unknown;
-    GrDomHooksManager: unknown;
-    GrDomHook: unknown;
-    GrEtagDecorator: unknown;
-    GrThemeApi: unknown;
-    SiteBasedCache: unknown;
-    FetchPromisesCache: unknown;
-    GrRestApiHelper: unknown;
-    GrLinkTextParser: unknown;
-    GrPluginEndpoints: unknown;
-    GrReviewerUpdatesParser: unknown;
-    GrPopupInterface: unknown;
-    GrCountStringFormatter: unknown;
-    GrReviewerSuggestionsProvider: unknown;
     util: unknown;
     Auth: unknown;
     EventEmitter: unknown;
-    GrAdminApi: unknown;
-    GrAnnotationActionsContext: unknown;
-    GrAnnotationActionsInterface: unknown;
-    GrChangeMetadataApi: unknown;
-    GrEmailSuggestionsProvider: unknown;
-    GrGroupSuggestionsProvider: unknown;
-    GrEventHelper: unknown;
-    GrPluginRestApi: unknown;
-    GrRepoApi: unknown;
-    GrSettingsApi: unknown;
-    GrStylesApi: unknown;
     PluginLoader: unknown;
+    // Heads up! There is a known plugin dependency on GrPluginActionContext.
     GrPluginActionContext: unknown;
     _apiUtils: {};
   }