Add filter to projects page

Change-Id: I0d5167ee8cd1391b56dbb4e140d17f17f73f208a
This commit is contained in:
Becky Siegel
2017-05-30 22:05:47 -07:00
parent 87d50f367c
commit 1510bcfde2
6 changed files with 140 additions and 20 deletions

View File

@@ -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/base-url-behavior/base-url-behavior.html">
<link rel="import" href="../../../behaviors/gr-url-encoding-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="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.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; border-collapse: collapse;
width: 100%; width: 100%;
} }
#filterContainer {
margin: 1em;
}
#projectFilter {
font-size: 1em;
max-width: 25em;
}
td { td {
flex-shrink: 0; flex-shrink: 0;
padding: .3em .5em; padding: .3em .5em;
@@ -71,6 +79,14 @@ limitations under the License.
padding: 1em var(--default-horizontal-margin); padding: 1em var(--default-horizontal-margin);
} }
</style> </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"> <table id="projectList">
<tr class="headerRow"> <tr class="headerRow">
<th class="name topHeader">Project Name</th> <th class="name topHeader">Project Name</th>
@@ -99,10 +115,10 @@ limitations under the License.
</table> </table>
<nav> <nav>
<a id="prevArrow" <a id="prevArrow"
href$="[[_computeNavLink(_offset, -1, _projectsPerPage)]]" href$="[[_computeNavLink(_offset, -1, _projectsPerPage, _filter)]]"
hidden$="[[_hidePrevArrow(_offset)]]" hidden>&larr; Prev</a> hidden$="[[_hidePrevArrow(_offset)]]" hidden>&larr; Prev</a>
<a id="nextArrow" <a id="nextArrow"
href$="[[_computeNavLink(_offset, 1, _projectsPerPage)]]" href$="[[_computeNavLink(_offset, 1, _projectsPerPage, _filter)]]"
hidden$="[[_hideNextArrow(_loading, _projects)]]" hidden> hidden$="[[_hideNextArrow(_loading, _projects)]]" hidden>
Next &rarr;</a> Next &rarr;</a>
</nav> </nav>

View File

@@ -14,6 +14,8 @@
(function() { (function() {
'use strict'; 'use strict';
const REQUEST_DEBOUNCE_INTERVAL_MS = 200;
Polymer({ Polymer({
is: 'gr-admin-project-list', is: 'gr-admin-project-list',
@@ -51,6 +53,7 @@
type: Boolean, type: Boolean,
value: true, value: true,
}, },
_filter: String,
}, },
behaviors: [ behaviors: [
@@ -63,16 +66,35 @@
'previous-page': '_handlePreviousPage', '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) { _paramsChanged(value) {
this._loading = true; this._loading = true;
if (value) {
this._filter = value.filter || null;
}
if (value && value.offset) { if (value && value.offset) {
this._offset = value.offset; this._offset = value.offset;
} else { } else {
this._offset = 0; 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 => { .then(projects => {
if (!projects) { if (!projects) {
this._projects = []; this._projects = [];
@@ -106,11 +128,14 @@
return webLinks.length ? webLinks : null; 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 could be a string when passed from the router.
offset = +(offset || 0); offset = +(offset || 0);
const newOffset = Math.max(0, offset + (projectsPerPage * direction)); const newOffset = Math.max(0, offset + (projectsPerPage * direction));
let href = this.getBaseUrl() + '/admin/projects'; let href = this.getBaseUrl() + '/admin/projects';
if (filter) {
href += '/q/filter:' + filter;
}
if (newOffset > 0) { if (newOffset > 0) {
href += ',' + newOffset; href += ',' + newOffset;
} }
@@ -132,17 +157,5 @@
} }
return loading || lastPage || !projects || !projects.length; 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));
},
}); });
})(); })();

View File

@@ -52,8 +52,18 @@ limitations under the License.
suite('gr-admin-project-list tests', () => { suite('gr-admin-project-list tests', () => {
let element; let element;
let projects; let projects;
let sandbox;
let value; let value;
setup(() => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
});
teardown(() => {
sandbox.restore();
});
suite('list with projects', () => { suite('list with projects', () => {
setup(done => { setup(done => {
projects = _.times(26, projectGenerator); projects = _.times(26, projectGenerator);
@@ -64,7 +74,6 @@ limitations under the License.
}, },
}); });
element = fixture('basic');
element._paramsChanged(value).then(() => { flush(done); }); element._paramsChanged(value).then(() => { flush(done); });
}); });
@@ -115,7 +124,6 @@ limitations under the License.
}, },
}); });
element = fixture('basic');
element._paramsChanged(value).then(() => { flush(done); }); element._paramsChanged(value).then(() => { flush(done); });
}); });
@@ -135,5 +143,55 @@ limitations under the License.
assert.equal(element._shownProjects.length, 25); 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> </script>

View File

@@ -113,6 +113,22 @@
app.params = { app.params = {
view: 'gr-admin-project-list', view: 'gr-admin-project-list',
offset: data.params[1] || 0, offset: data.params[1] || 0,
filter: null,
};
});
page('/admin/projects/q/filter::filter,:offset', loadUser, data => {
app.params = {
view: 'gr-admin-project-list',
offset: data.params.offset,
filter: data.params.filter,
};
});
page('/admin/projects/q/filter::filter', loadUser, data => {
app.params = {
view: 'gr-admin-project-list',
filter: data.params.filter || null,
}; };
}); });

View File

@@ -559,10 +559,12 @@
}); });
}, },
getProjects(projectsPerPage, opt_offset) { getProjects(filter, projectsPerPage, opt_offset) {
const offset = opt_offset || 0; const offset = opt_offset || 0;
filter = filter ? '&m=' + filter : '';
return this._fetchSharedCacheURL( return this._fetchSharedCacheURL(
`/projects/?d&n=${projectsPerPage + 1}&S=${offset}` `/projects/?d&n=${projectsPerPage + 1}&S=${offset}${filter}`
); );
}, },

View File

@@ -643,5 +643,20 @@ limitations under the License.
'POST', '/changes/foo/revisions/bar/comments/01234/delete', 'POST', '/changes/foo/revisions/bar/comments/01234/delete',
{reason: 'removal reason'})); {reason: 'removal reason'}));
}); });
test('getProjects', () => {
sandbox.stub(element, '_fetchSharedCacheURL');
element.getProjects('test', 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0&m=test'));
element.getProjects(null, 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=0'));
element.getProjects('test', 25, 25);
assert.isTrue(element._fetchSharedCacheURL.lastCall
.calledWithExactly('/projects/?d&n=26&S=25&m=test'));
});
}); });
</script> </script>