Support displaying dynamic content and summary cells in gr-file-list

The main motivation is to support displaying code coverage percentages,
but the design is made to be generate to support other use cases as
needed.
The cells will remain hidden until column headers are in place,
which will be implemented in a separate CL.

Change-Id: Ib52ebdda199aa206c72ae47be218ac15cfb9346c
Bug: crbug.com/939904
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index a51f848..6ac2195 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -384,6 +384,20 @@
                 [[_formatPercentage(file.size, file.size_delta)]]
               </span>
             </div>
+            <template is="dom-if" if="[[_showDynamicColumns]]">
+              <template is="dom-repeat" items="[[_dynamicContentEndpoints]]" as="contentEndpoint">
+                <div class$="[[_computeClass('', file.__path)]]">
+                  <gr-endpoint-decorator name="[[contentEndpoint]]">
+                    <gr-endpoint-param name="changeNum" value="[[changeNum]]">
+                    </gr-endpoint-param>
+                    <gr-endpoint-param name="patchRange" value="[[patchRange]]">
+                    </gr-endpoint-param>
+                    <gr-endpoint-param name="path" value="[[file.__path]]">
+                    </gr-endpoint-param>
+                  </gr-endpoint-decorator>
+                </div>
+              </template>
+            </template>
             <div class="reviewed hideOnEdit" hidden$="[[!_loggedIn]]" hidden>
               <span class$="reviewedLabel [[_computeReviewedClass(file.isReviewed)]]">Reviewed</span>
               <label>
@@ -448,6 +462,12 @@
           -[[_patchChange.deleted]]
         </span>
       </div>
+      <template is="dom-if" if="[[_showDynamicColumns]]">
+        <template is="dom-repeat" items="[[_dynamicSummaryEndpoints]]" as="summaryEndpoint">
+          <gr-endpoint-decorator name="[[summaryEndpoint]]">
+          </gr-endpoint-decorator>
+        </template>
+      </template>
       <!-- Empty div here exists to keep spacing in sync with file rows. -->
       <div class="reviewed hideOnEdit" hidden$="[[!_loggedIn]]"></div>
       <div class="editFileControls showOnEdit"></div>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index ef69ae4..55785f4 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -180,6 +180,23 @@
 
       /** @type {Function} */
       _cancelForEachDiff: Function,
+
+      _showDynamicColumns: {
+        type: Boolean,
+        computed: '_computeShowDynamicColumns(_dynamicHeaderEndpoints)',
+      },
+      /** @type {Array<string>} */
+      _dynamicHeaderEndpoints: {
+        type: Array,
+      },
+      /** @type {Array<string>} */
+      _dynamicContentEndpoints: {
+        type: Array,
+      },
+      /** @type {Array<string>} */
+      _dynamicSummaryEndpoints: {
+        type: Array,
+      },
     },
 
     behaviors: [
@@ -229,6 +246,28 @@
       keydown: '_scopedKeydownHandler',
     },
 
+    attached() {
+      Gerrit.awaitPluginsLoaded().then(() => {
+        this._dynamicHeaderEndpoints = Gerrit._endpoints.getDynamicEndpoints(
+            'change-view-file-list-header');
+        this._dynamicContentEndpoints = Gerrit._endpoints.getDynamicEndpoints(
+            'change-view-file-list-content');
+        this._dynamicSummaryEndpoints = Gerrit._endpoints.getDynamicEndpoints(
+            'change-view-file-list-summary');
+
+        if (this._dynamicHeaderEndpoints.length !==
+            this._dynamicContentEndpoints.length) {
+          console.warn(
+              'Different number of dynamic file-list header and content.');
+        }
+        if (this._dynamicHeaderEndpoints.length !==
+            this._dynamicSummaryEndpoints.length) {
+          console.warn(
+              'Different number of dynamic file-list headers and summary.');
+        }
+      });
+    },
+
     detached() {
       this._cancelDiffs();
     },
@@ -805,7 +844,10 @@
      * @param {string} path
      */
     _computeClass(baseClass, path) {
-      const classes = [baseClass];
+      const classes = [];
+      if (baseClass) {
+        classes.push(baseClass);
+      }
       if (path === this.COMMIT_MESSAGE_PATH || path === this.MERGE_LIST_PATH) {
         classes.push('invisible');
       }
@@ -1253,6 +1295,15 @@
       return `sizeBars desktop ${hideClass}`;
     },
 
+    _computeShowDynamicColumns(dynamicHeaderEndpoints) {
+      // During a design review, it was decided that dynamic columns should
+      // remain hidden until column headers (including existing columns such as
+      // "Comments") are in place to avoid confusion.
+      // TODO(crbug.com/939904): Enable dispaying dynamic columns when there is
+      // at least one of them registered.
+      return false;
+    },
+
     /**
      * Returns true if none of the inline diffs have been expanded.
      * @return {boolean}