Merge "Move thread formation logic to gr-comment-api"
diff --git a/WORKSPACE b/WORKSPACE
index 3c30026..fff9235 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -51,10 +51,10 @@
 
 http_archive(
     name = "com_google_protobuf",
-    sha256 = "71030a04aedf9f612d2991c1c552317038c3c5a2b578ac4745267a45e7037c29",
-    strip_prefix = "protobuf-3.12.3",
+    sha256 = "d0f5f605d0d656007ce6c8b5a82df3037e1d8fe8b121ed42e536f569dec16113",
+    strip_prefix = "protobuf-3.14.0",
     urls = [
-        "https://github.com/protocolbuffers/protobuf/archive/v3.12.3.tar.gz",
+        "https://github.com/protocolbuffers/protobuf/archive/v3.14.0.tar.gz",
     ],
 )
 
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 2582170..e5a1586 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
@@ -80,7 +80,9 @@
       return '';
     }
 
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     return this.$.restAPI
       .getGroupAuditLog(this.groupId, errFn)
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 1cd55ca..01571a2 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
@@ -140,7 +140,9 @@
 
     const promises: Promise<void>[] = [];
 
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     return this.$.restAPI.getGroupConfig(this.groupId, errFn).then(config => {
       if (!config || !config.name) {
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 95a6e5d..4525543 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -145,7 +145,9 @@
 
     const promises: Promise<unknown>[] = [];
 
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     return this.$.restAPI.getGroupConfig(this.groupId, errFn).then(config => {
       if (!config || !config.name) {
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 922f592..9337042 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
@@ -98,7 +98,9 @@
   }
 
   _getPlugins(filter: string, pluginsPerPage: number, offset?: number) {
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
     return this.$.restAPI
       .getPlugins(filter, pluginsPerPage, offset, errFn)
       .then(plugins => {
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 fde7234..31e1f65 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
@@ -155,7 +155,9 @@
   }
 
   _reload(repo: RepoName) {
-    const errFn = (response?: Response | null) => firePageError(this, response);
+    const errFn = (response?: Response | null) => {
+      firePageError(this, response);
+    };
 
     this._editing = false;
 
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 f2735fb..99f85fa 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
@@ -62,7 +62,9 @@
       return Promise.resolve();
     }
 
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     return this.$.restAPI
       .getRepoDashboards(repo, errFn)
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 e4e9d34..17414c0 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
@@ -182,7 +182,9 @@
     this._loading = true;
     this._items = [];
     flush();
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     if (detailType === RepoDetailView.BRANCHES) {
       return this.$.restAPI
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 3acf8fa..426e512 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -176,7 +176,9 @@
 
     const promises = [];
 
-    const errFn: ErrorCallback = response => firePageError(this, response);
+    const errFn: ErrorCallback = response => {
+      firePageError(this, response);
+    };
 
     promises.push(
       this._getLoggedIn().then(loggedIn => {
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 dbaed07..ce3a811 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
@@ -150,7 +150,9 @@
     project: RepoName,
     dashboard: DashboardId
   ): Promise<UserDashboard | undefined> {
-    const errFn = (response?: Response | null) => firePageError(this, response);
+    const errFn = (response?: Response | null) => {
+      firePageError(this, response);
+    };
     return this.$.restAPI
       .getDashboard(project, dashboard, errFn)
       .then(response => {
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 f8a5940..6b04153 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
@@ -76,6 +76,13 @@
 import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 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';
+import {KnownExperimentId} from '../../../services/flags/flags';
+import {
+  Metadata,
+  isSectionSet,
+  DisplayRules,
+} from '../../../utils/change-metadata-util';
 
 const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
 
@@ -194,6 +201,25 @@
   @property({type: Object})
   _CHANGE_ROLE = ChangeRole;
 
+  @property({type: Object})
+  _SECTION = Metadata;
+
+  @property({type: Boolean})
+  _showAllSections = false;
+
+  @property({type: Boolean})
+  _isNewChangeSummaryUiEnabled = false;
+
+  flagsService = appContext.flagsService;
+
+  /** @override */
+  ready() {
+    super.ready();
+    this._isNewChangeSummaryUiEnabled = this.flagsService.isEnabled(
+      KnownExperimentId.NEW_CHANGE_SUMMARY_UI
+    );
+  }
+
   @observe('change.labels')
   _labelsChanged(labels?: LabelNameToInfoMap) {
     this.labels = {...labels} || null;
@@ -566,6 +592,35 @@
     return this._getNonOwnerRole(change, role) ? '' : 'hideDisplay';
   }
 
+  _computeDisplayState(
+    showAllSections: boolean,
+    change: ParsedChangeInfo | undefined,
+    section: Metadata
+  ) {
+    if (
+      !this._isNewChangeSummaryUiEnabled ||
+      showAllSections ||
+      DisplayRules.ALWAYS_SHOW.includes(section) ||
+      (DisplayRules.SHOW_IF_SET.includes(section) &&
+        isSectionSet(section, change))
+    ) {
+      return '';
+    }
+    return 'hideDisplay';
+  }
+
+  _computeShowAllLabelText(showAllSections: boolean) {
+    if (showAllSections) {
+      return 'Show less';
+    } else {
+      return 'Show all';
+    }
+  }
+
+  _onShowAllClick() {
+    this._showAllSections = !this._showAllSections;
+  }
+
   /**
    * Get the user with the specified role on the change. Returns null if the
    * user with that role is the same as the owner.
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 f1d1127..88f7351 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
@@ -94,9 +94,31 @@
       --account-max-length: 120px;
       max-width: 285px;
     }
+    .metadata-title {
+      font-weight: var(--font-weight-bold);
+      color: var(--deemphasized-text-color);
+      padding-left: var(--metadata-horizontal-padding);
+    }
+    .metadata-header {
+      display: flex;
+      justify-content: space-between;
+    }
   </style>
   <gr-external-style id="externalStyle" name="change-metadata">
-    <section>
+    <template is="dom-if" if="[[_isNewChangeSummaryUiEnabled]]">
+      <div class="metadata-header">
+        <h3 class="metadata-title">Change Info</h3>
+        <gr-button
+          class="show-all-button"
+          on-click="_onShowAllClick"
+          no-uppercase=""
+          >[[_computeShowAllLabelText(_showAllSections)]]</gr-button
+        >
+      </div>
+    </template>
+    <section
+      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.UPDATED)]]"
+    >
       <span class="title">Updated</span>
       <span class="value">
         <gr-date-formatter
@@ -105,7 +127,9 @@
         ></gr-date-formatter>
       </span>
     </section>
-    <section>
+    <section
+      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.OWNER)]]"
+    >
       <span class="title">Owner</span>
       <span class="value">
         <gr-account-chip
@@ -156,7 +180,9 @@
       </span>
     </section>
     <template is="dom-if" if="[[_isAssigneeEnabled(serverConfig)]]">
-      <section class="assignee">
+      <section
+        class$="assignee [[_computeDisplayState(_showAllSections, change, _SECTION.ASSIGNEE)]]"
+      >
         <span class="title">Assignee</span>
         <span class="value">
           <gr-account-list
@@ -172,7 +198,9 @@
         </span>
       </section>
     </template>
-    <section>
+    <section
+      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REVIEWERS)]]"
+    >
       <span class="title">Reviewers</span>
       <span class="value">
         <gr-reviewer-list
@@ -183,7 +211,9 @@
         ></gr-reviewer-list>
       </span>
     </section>
-    <section>
+    <section
+      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.CC)]]"
+    >
       <span class="title">CC</span>
       <span class="value">
         <gr-reviewer-list
@@ -198,7 +228,9 @@
       is="dom-if"
       if="[[_computeShowRepoBranchTogether(change.project, change.branch)]]"
     >
-      <section>
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REPO_BRANCH)]]"
+      >
         <span class="title">Repo | Branch</span>
         <span class="value">
           <a href$="[[_computeProjectUrl(change.project)]]"
@@ -215,7 +247,9 @@
       is="dom-if"
       if="[[!_computeShowRepoBranchTogether(change.project, change.branch)]]"
     >
-      <section>
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REPO_BRANCH)]]"
+      >
         <span class="title">Repo</span>
         <span class="value">
           <a href$="[[_computeProjectUrl(change.project)]]">
@@ -226,7 +260,9 @@
           </a>
         </span>
       </section>
-      <section>
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REPO_BRANCH)]]"
+      >
         <span class="title">Branch</span>
         <span class="value">
           <a href$="[[_computeBranchUrl(change.project, change.branch)]]">
@@ -238,7 +274,9 @@
         </span>
       </section>
     </template>
-    <section>
+    <section
+      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.PARENT)]]"
+    >
       <span class="title">[[_computeParentsLabel(_currentParents)]]</span>
       <span class="value">
         <ol
@@ -262,7 +300,9 @@
         </ol>
       </span>
     </section>
-    <section class="topic">
+    <section
+      class$="topic [[_computeDisplayState(_showAllSections, change, _SECTION.TOPIC)]]"
+    >
       <span class="title">Topic</span>
       <span class="value">
         <template is="dom-if" if="[[_showTopicChip(change.*, _settingTopic)]]">
@@ -288,7 +328,9 @@
       </span>
     </section>
     <template is="dom-if" if="[[_showCherryPickOf(change.*)]]">
-      <section>
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.CHERRY_PICK_OF)]]"
+      >
         <span class="title">Cherry pick of</span>
         <span class="value">
           <a
@@ -304,14 +346,16 @@
       </section>
     </template>
     <section
-      class="strategy"
+      class$="strategy [[_computeDisplayState(_showAllSections, change, _SECTION.STRATEGY)]]"
       hidden$="[[_computeHideStrategy(change)]]"
       hidden=""
     >
       <span class="title">Strategy</span>
       <span class="value">[[_computeStrategy(change)]]</span>
     </section>
-    <section class="hashtag">
+    <section
+      class$="hashtag [[_computeDisplayState(_showAllSections, change, _SECTION.HASHTAGS)]]"
+    >
       <span class="title">Hashtags</span>
       <span class="value">
         <template is="dom-repeat" items="[[change.hashtags]]">
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 684a58a..43ed77f 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
@@ -226,9 +226,10 @@
             bubbles: true,
           })
         );
+      } else {
+        this.lastDisplayedNavigateToNextFileToast = Date.now();
+        fireAlert(this, 'Press n again to navigate to next unreviewed file');
       }
-      this.lastDisplayedNavigateToNextFileToast = Date.now();
-      fireAlert(this, 'Press n again to navigate to next unreviewed file');
     }
 
     this._fixSide();
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index c15634b..2915acd 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -210,10 +210,12 @@
   created() {
     super.created();
     this._bindKeyboardShortcuts();
-    this.addEventListener(EventType.PAGE_ERROR, e => this._handlePageError(e));
-    this.addEventListener(EventType.TITLE_CHANGE, e =>
-      this._handleTitleChange(e)
-    );
+    this.addEventListener(EventType.PAGE_ERROR, e => {
+      this._handlePageError(e);
+    });
+    this.addEventListener(EventType.TITLE_CHANGE, e => {
+      this._handleTitleChange(e);
+    });
     this.addEventListener('location-change', e =>
       this._handleLocationChange(e)
     );
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index e40412d..ba33954 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -27,4 +27,5 @@
   PATCHSET_COMMENTS = 'UiFeature__patchset_comments',
   NEW_CONTEXT_CONTROLS = 'UiFeature__new_context_controls',
   CI_REBOOT_CHECKS = 'UiFeature__ci_reboot_checks',
+  NEW_CHANGE_SUMMARY_UI = 'UiFeature__new_change_summary_ui',
 }
diff --git a/polygerrit-ui/app/utils/change-metadata-util.ts b/polygerrit-ui/app/utils/change-metadata-util.ts
new file mode 100644
index 0000000..6ce1483
--- /dev/null
+++ b/polygerrit-ui/app/utils/change-metadata-util.ts
@@ -0,0 +1,75 @@
+/**
+ * @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 {ParsedChangeInfo} from '../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
+
+export enum Metadata {
+  OWNER = 'Owner',
+  REVIEWERS = 'Reviewers',
+  REPO_BRANCH = 'Repo | Branch',
+  SUBMITTED = 'Submitted',
+  PARENT = 'Parent',
+  STRATEGY = 'Strategy',
+  UPDATED = 'Updated',
+  CC = 'CC',
+  HASHTAGS = 'Hashtags',
+  TOPIC = 'Topic',
+  UPLOADER = 'Uploader',
+  AUTHOR = 'Author',
+  COMMITTER = 'Committer',
+  ASSIGNEE = 'Assignee',
+  CHERRY_PICK_OF = 'Cherry pick of',
+}
+
+export const DisplayRules = {
+  ALWAYS_SHOW: [
+    Metadata.OWNER,
+    Metadata.REVIEWERS,
+    Metadata.REPO_BRANCH,
+    Metadata.SUBMITTED,
+  ],
+  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],
+};
+
+export function isSectionSet(section: Metadata, change?: ParsedChangeInfo) {
+  switch (section) {
+    case Metadata.CC:
+      return !!change?.reviewers?.CC?.length;
+    case Metadata.HASHTAGS:
+      return !!change?.hashtags?.length;
+    case Metadata.TOPIC:
+      return !!change?.topic;
+    case Metadata.UPLOADER:
+    case Metadata.AUTHOR:
+    case Metadata.COMMITTER:
+    case Metadata.ASSIGNEE:
+      return false;
+    case Metadata.CHERRY_PICK_OF:
+      return !!change?.cherry_pick_of_change;
+  }
+  return true;
+}