Add filter to projects page
Change-Id: I0d5167ee8cd1391b56dbb4e140d17f17f73f208a
This commit is contained in:
		@@ -16,6 +16,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 | 
			
		||||
<link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
 | 
			
		||||
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
 | 
			
		||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
 | 
			
		||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 | 
			
		||||
 | 
			
		||||
@@ -35,6 +36,13 @@ limitations under the License.
 | 
			
		||||
        border-collapse: collapse;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
      #filterContainer {
 | 
			
		||||
        margin: 1em;
 | 
			
		||||
      }
 | 
			
		||||
      #projectFilter {
 | 
			
		||||
        font-size: 1em;
 | 
			
		||||
        max-width: 25em;
 | 
			
		||||
      }
 | 
			
		||||
      td {
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        padding: .3em .5em;
 | 
			
		||||
@@ -71,6 +79,14 @@ limitations under the License.
 | 
			
		||||
        padding: 1em var(--default-horizontal-margin);
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
    <div id="filterContainer">
 | 
			
		||||
      <label>Filter:</label>
 | 
			
		||||
      <input is="iron-input"
 | 
			
		||||
          type="text"
 | 
			
		||||
          id="projectFilter"
 | 
			
		||||
          bind-value="{{_filter}}"
 | 
			
		||||
          on-input="_onValueChange">
 | 
			
		||||
    </div>
 | 
			
		||||
    <table id="projectList">
 | 
			
		||||
      <tr class="headerRow">
 | 
			
		||||
        <th class="name topHeader">Project Name</th>
 | 
			
		||||
@@ -99,10 +115,10 @@ limitations under the License.
 | 
			
		||||
    </table>
 | 
			
		||||
    <nav>
 | 
			
		||||
      <a id="prevArrow"
 | 
			
		||||
          href$="[[_computeNavLink(_offset, -1, _projectsPerPage)]]"
 | 
			
		||||
          href$="[[_computeNavLink(_offset, -1, _projectsPerPage, _filter)]]"
 | 
			
		||||
          hidden$="[[_hidePrevArrow(_offset)]]" hidden>← Prev</a>
 | 
			
		||||
      <a id="nextArrow"
 | 
			
		||||
          href$="[[_computeNavLink(_offset, 1, _projectsPerPage)]]"
 | 
			
		||||
          href$="[[_computeNavLink(_offset, 1, _projectsPerPage, _filter)]]"
 | 
			
		||||
          hidden$="[[_hideNextArrow(_loading, _projects)]]" hidden>
 | 
			
		||||
        Next →</a>
 | 
			
		||||
    </nav>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@
 | 
			
		||||
(function() {
 | 
			
		||||
  'use strict';
 | 
			
		||||
 | 
			
		||||
  const REQUEST_DEBOUNCE_INTERVAL_MS = 200;
 | 
			
		||||
 | 
			
		||||
  Polymer({
 | 
			
		||||
    is: 'gr-admin-project-list',
 | 
			
		||||
 | 
			
		||||
@@ -51,6 +53,7 @@
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        value: true,
 | 
			
		||||
      },
 | 
			
		||||
      _filter: String,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    behaviors: [
 | 
			
		||||
@@ -63,16 +66,35 @@
 | 
			
		||||
      'previous-page': '_handlePreviousPage',
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onValueChange(e) {
 | 
			
		||||
      this.debounce('reload', () => {
 | 
			
		||||
        if (e.target.value) {
 | 
			
		||||
          return page.show('/admin/projects/q/filter:' +
 | 
			
		||||
              this.encodeURL(e.target.value, false));
 | 
			
		||||
        }
 | 
			
		||||
        page.show('/admin/projects');
 | 
			
		||||
      }, REQUEST_DEBOUNCE_INTERVAL_MS);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _paramsChanged(value) {
 | 
			
		||||
      this._loading = true;
 | 
			
		||||
 | 
			
		||||
      if (value) {
 | 
			
		||||
        this._filter = value.filter || null;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (value && value.offset) {
 | 
			
		||||
        this._offset = value.offset;
 | 
			
		||||
      } else {
 | 
			
		||||
        this._offset = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return this.$.restAPI.getProjects(this._projectsPerPage, this._offset)
 | 
			
		||||
      return this._getProjects(this._filter, this._projectsPerPage,
 | 
			
		||||
          this._offset);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getProjects(filter, projectsPerPage, offset) {
 | 
			
		||||
      return this.$.restAPI.getProjects(filter, projectsPerPage, offset)
 | 
			
		||||
          .then(projects => {
 | 
			
		||||
            if (!projects) {
 | 
			
		||||
              this._projects = [];
 | 
			
		||||
@@ -106,11 +128,14 @@
 | 
			
		||||
      return webLinks.length ? webLinks : null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _computeNavLink(offset, direction, projectsPerPage) {
 | 
			
		||||
    _computeNavLink(offset, direction, projectsPerPage, filter) {
 | 
			
		||||
      // Offset could be a string when passed from the router.
 | 
			
		||||
      offset = +(offset || 0);
 | 
			
		||||
      const newOffset = Math.max(0, offset + (projectsPerPage * direction));
 | 
			
		||||
      let href = this.getBaseUrl() + '/admin/projects';
 | 
			
		||||
      if (filter) {
 | 
			
		||||
        href += '/q/filter:' + filter;
 | 
			
		||||
      }
 | 
			
		||||
      if (newOffset > 0) {
 | 
			
		||||
        href += ',' + newOffset;
 | 
			
		||||
      }
 | 
			
		||||
@@ -132,17 +157,5 @@
 | 
			
		||||
      }
 | 
			
		||||
      return loading || lastPage || !projects || !projects.length;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleNextPage() {
 | 
			
		||||
      if (this.$.nextArrow.hidden) { return; }
 | 
			
		||||
      page.show(this._computeNavLink(
 | 
			
		||||
          this._offset, 1, this._projectsPerPage));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handlePreviousPage() {
 | 
			
		||||
      if (this.$.prevArrow.hidden) { return; }
 | 
			
		||||
      page.show(this._computeNavLink(
 | 
			
		||||
          this._offset, -1, this._projectsPerPage));
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
})();
 | 
			
		||||
 
 | 
			
		||||
@@ -52,8 +52,18 @@ limitations under the License.
 | 
			
		||||
  suite('gr-admin-project-list tests', () => {
 | 
			
		||||
    let element;
 | 
			
		||||
    let projects;
 | 
			
		||||
    let sandbox;
 | 
			
		||||
    let value;
 | 
			
		||||
 | 
			
		||||
    setup(() => {
 | 
			
		||||
      sandbox = sinon.sandbox.create();
 | 
			
		||||
      element = fixture('basic');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    teardown(() => {
 | 
			
		||||
      sandbox.restore();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    suite('list with projects', () => {
 | 
			
		||||
      setup(done => {
 | 
			
		||||
        projects = _.times(26, projectGenerator);
 | 
			
		||||
@@ -64,7 +74,6 @@ limitations under the License.
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        element = fixture('basic');
 | 
			
		||||
        element._paramsChanged(value).then(() => { flush(done); });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +124,6 @@ limitations under the License.
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        element = fixture('basic');
 | 
			
		||||
        element._paramsChanged(value).then(() => { flush(done); });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@@ -135,5 +143,55 @@ limitations under the License.
 | 
			
		||||
        assert.equal(element._shownProjects.length, 25);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    suite('filter', () => {
 | 
			
		||||
      test('_onValueChange', done => {
 | 
			
		||||
        sandbox.stub(page, 'show', url => {
 | 
			
		||||
          assert.equal(url, '/admin/projects/q/filter:test');
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
        const e = {target: {value: 'test'}};
 | 
			
		||||
        element._onValueChange(e);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      test('_paramsChanged', done => {
 | 
			
		||||
        sandbox.stub(element.$.restAPI, 'getProjects', () => {
 | 
			
		||||
          return Promise.resolve(projects);
 | 
			
		||||
        });
 | 
			
		||||
        const value = {
 | 
			
		||||
          filter: 'test',
 | 
			
		||||
          offset: 25,
 | 
			
		||||
        };
 | 
			
		||||
        element._paramsChanged(value).then(() => {
 | 
			
		||||
          assert.isTrue(element.$.restAPI.getProjects.lastCall
 | 
			
		||||
              .calledWithExactly('test', 25, 25));
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      test('_computeNavLink', () => {
 | 
			
		||||
        const offset = 25;
 | 
			
		||||
        const projectsPerPage = 25;
 | 
			
		||||
        const filter = 'test';
 | 
			
		||||
 | 
			
		||||
        sandbox.stub(element, 'getBaseUrl', () => '');
 | 
			
		||||
 | 
			
		||||
        assert.equal(
 | 
			
		||||
            element._computeNavLink(offset, 1, projectsPerPage, filter),
 | 
			
		||||
            '/admin/projects/q/filter:test,50');
 | 
			
		||||
 | 
			
		||||
        assert.equal(
 | 
			
		||||
            element._computeNavLink(offset, -1, projectsPerPage, filter),
 | 
			
		||||
            '/admin/projects/q/filter:test');
 | 
			
		||||
 | 
			
		||||
        assert.equal(
 | 
			
		||||
            element._computeNavLink(offset, 1, projectsPerPage, null),
 | 
			
		||||
            '/admin/projects,50');
 | 
			
		||||
 | 
			
		||||
        assert.equal(
 | 
			
		||||
            element._computeNavLink(offset, -1, projectsPerPage, null),
 | 
			
		||||
            '/admin/projects');
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user