Limit displayed checks to 20 and add Show All checks button.

Change-Id: I5e6718ec5072e1de04f4b543469ceac44819629e
diff --git a/gr-checks/gr-checks-view.html b/gr-checks/gr-checks-view.html
index 7ab60f9..0048046 100644
--- a/gr-checks/gr-checks-view.html
+++ b/gr-checks/gr-checks-view.html
@@ -110,6 +110,11 @@
         display: flex;
         align-items: center;
       }
+
+      .show-more-checks {
+        margin: 0 0 var(--spacing-l) var(--spacing-l);
+      }
+
     </style>
 
     <header>
@@ -208,10 +213,15 @@
           </template>
         </tbody>
       </table>
+      <template is="dom-if" if="[[_showMoreChecksButton]]">
+        <gr-button class="show-more-checks" on-click="_toggleShowChecks">
+          [[_computeShowText(_showAllChecks)]]
+        </gr-button>
+      </template>
     </template>
 
     <gr-checkers-list on-resize="_handleCheckersListResize" plugin-rest-api="[[pluginRestApi]]"></gr-checkers-list>
 
   </template>
   <script src="gr-checks-view.js"></script>
-</dom-module>
+</dom-module>
\ No newline at end of file
diff --git a/gr-checks/gr-checks-view.js b/gr-checks/gr-checks-view.js
index d15e12d..c08926a 100644
--- a/gr-checks/gr-checks-view.js
+++ b/gr-checks/gr-checks-view.js
@@ -17,6 +17,7 @@
   const CheckStateFilters = [STATE_ALL, ...StatusPriorityOrder];
 
   const CHECKS_POLL_INTERVAL_MS = 60 * 1000;
+  const CHECKS_LIMIT = 20;
 
   /**
    * @typedef {{
@@ -87,12 +88,22 @@
         type: Boolean,
         value: false,
       },
+      _showAllChecks: {
+        type: Boolean,
+        value: false,
+      },
+      _filteredChecks: Array,
+      _showMoreChecksButton: {
+        type: Boolean,
+        value: false,
+        notify: true,
+      },
     },
 
     observers: [
       '_pollChecksRegularly(change, _currentPatchSet, getChecks)',
       '_updateVisibleChecks(_checks.*, _currentStatus, ' +
-          '_showBlockingChecksOnly)',
+          '_showBlockingChecksOnly, _showAllChecks)',
     ],
 
     attached() {
@@ -111,6 +122,10 @@
       this.unlisten(document, 'visibilitychange', '_onVisibililityChange');
     },
 
+    _toggleShowChecks() {
+      this._showAllChecks = !this._showAllChecks;
+    },
+
     _computePatchSetDropdownItems(change) {
       return Object.values(change.revisions)
           .filter(patch => patch._number !== 'edit')
@@ -123,10 +138,15 @@
           .sort((a, b) => b.value - a.value);
     },
 
-    _updateVisibleChecks(checksRecord, status, showBlockingChecksOnly) {
+    _computeShowText(showAllChecks) {
+      return showAllChecks ? 'Show Less' : 'Show All';
+    },
+
+    _updateVisibleChecks(checksRecord, status, showBlockingChecksOnly,
+        showAllChecks) {
       const checks = checksRecord.base;
       if (!checks) return [];
-      this._visibleChecks = checks.filter(check => {
+      this._filteredChecks = checks.filter(check => {
         if (showBlockingChecksOnly && (!check.blocking ||
             !check.blocking.length)) return false;
         return status === STATE_ALL || check.state === status;
@@ -137,6 +157,9 @@
       If not notified, then the message for the check is not displayed after
       clicking the toggle
       */
+      this._showMoreChecksButton = this._filteredChecks.length > CHECKS_LIMIT;
+      this._visibleChecks = this._filteredChecks.slice(0, showAllChecks ?
+        undefined : CHECKS_LIMIT);
       this._visibleChecks.forEach((val, idx) =>
         this.notifyPath(`_visibleChecks.${idx}.showCheckMessage`));
     },
diff --git a/gr-checks/gr-checks-view_test.html b/gr-checks/gr-checks-view_test.html
index f45dd46..ebb6c13 100644
--- a/gr-checks/gr-checks-view_test.html
+++ b/gr-checks/gr-checks-view_test.html
@@ -101,6 +101,7 @@
 
   const CHECKS_POLL_INTERVAL_MS = 60 * 1000;
   const STATE_ALL = 'ALL';
+  const CHECKS_LIMIT = 20;
 
   suite('gr-checks-view tests', async () => {
     await readyToTest();
@@ -471,6 +472,44 @@
         });
       });
     });
+
+    suite('with large number of checks', () => {
+      setup(done => {
+        const CHECK3 = Object.assign({}, CHECK1, {state: 'FAILED'});
+        const CHECK4 = Object.assign({}, CHECK1, {state: 'FAILED',
+          blocking: [1, 2, 3]});
+        const checks = [];
+        for (let i = 1;i <= 20;i++) {
+          checks.push(...[CHECK1, CHECK2, CHECK3, CHECK4]);
+        }
+        getChecksResolve(checks);
+        flush(done);
+      });
+
+      test('rendered checks are limited by default', () => {
+        assert.equal(element._visibleChecks.length, CHECKS_LIMIT);
+      });
+
+      test('show more button expands to show all checks', () => {
+        const showMoreChecksButton = element.querySelector('.show-more-checks');
+        assert.isOk(showMoreChecksButton);
+        showMoreChecksButton.click();
+        flush(() => {
+          assert.equal(element._visibleChecks.length, element._checks.length);
+        });
+      });
+
+      test('show more button hides if checks are below limit', () => {
+        element._currentStatus = Statuses.NOT_STARTED;
+        flush(() => {
+          const showMoreChecksButton = element.querySelector
+            ('.show-more-checks');
+          assert.equal(showMoreChecksButton.style.display, "none");
+        });
+      });
+
+    });
+
   });
 
 </script>