Merge pull request #4822 from hashicorp/b-ui-reset-page-param

UI: Reset page query param on search
This commit is contained in:
Michael Lange
2018-11-01 13:20:02 -07:00
committed by GitHub
12 changed files with 85 additions and 8 deletions

View File

@@ -12,6 +12,9 @@ export default Component.extend({
// Used to throttle sets to searchTerm
debounce: 150,
// A hook that's called when the search value changes
onChange() {},
classNames: ['search-box', 'field', 'has-addons'],
actions: {
@@ -23,5 +26,7 @@ export default Component.extend({
});
function updateSearch() {
this.set('searchTerm', this.get('_searchTerm'));
const newTerm = this.get('_searchTerm');
this.onChange(newTerm);
this.set('searchTerm', newTerm);
}

View File

@@ -36,6 +36,16 @@ export default Mixin.create({
fuzzySearchEnabled: false,
regexEnabled: true,
// Search should reset pagination. Not every instance of
// search will be paired with pagination, but it's still
// preferable to generalize this rather than risking it being
// forgotten on a single page.
resetPagination() {
if (this.get('currentPage') != null) {
this.set('currentPage', 1);
}
},
fuse: computed('listToSearch.[]', 'fuzzySearchProps.[]', function() {
return new Fuse(this.get('listToSearch'), {
shouldSort: true,

View File

@@ -98,6 +98,7 @@
<div>Allocations <span class="badge is-white">{{model.allocations.length}}</span></div>
{{search-box
searchTerm=(mut searchTerm)
onChange=(action resetPagination)
placeholder="Search allocations..."
class="is-inline pull-right"
inputClass="is-compact"}}

View File

@@ -4,7 +4,12 @@
{{else}}
{{#if nodes.length}}
<div class="content">
<div>{{search-box searchTerm=(mut searchTerm) placeholder="Search clients..."}}</div>
<div>
{{search-box
searchTerm=(mut searchTerm)
onChange=(action resetPagination)
placeholder="Search clients..."}}
</div>
</div>
{{/if}}
{{#list-pagination

View File

@@ -1,9 +1,9 @@
{{#if source.length}}
{{yield (hash
first=(component "list-pagination/list-pager" page=1 visible=(not (eq page 1)))
prev=(component "list-pagination/list-pager" page=(dec page) visible=(not (eq page 1)))
next=(component "list-pagination/list-pager" page=(inc page) visible=(not (eq page lastPage)))
last=(component "list-pagination/list-pager" page=lastPage visible=(not (eq page lastPage)))
first=(component "list-pagination/list-pager" test="first" page=1 visible=(not (eq page 1)))
prev=(component "list-pagination/list-pager" test="prev" page=(dec page) visible=(not (eq page 1)))
next=(component "list-pagination/list-pager" test="next" page=(inc page) visible=(not (eq page lastPage)))
last=(component "list-pagination/list-pager" test="last" page=lastPage visible=(not (eq page lastPage)))
pageLinks=pageLinks
currentPage=page
totalPages=lastPage

View File

@@ -1,5 +1,5 @@
{{#if visible}}
{{#link-to (query-params currentPage=page) class=attrs.class}}
{{#link-to (query-params currentPage=page) class=attrs.class data-test-pager=test}}
{{yield}}
{{/link-to}}
{{/if}}

View File

@@ -5,7 +5,11 @@
<div class="columns">
{{#if filteredJobs.length}}
<div class="column">
{{search-box data-test-jobs-search searchTerm=(mut searchTerm) placeholder="Search jobs..."}}
{{search-box
data-test-jobs-search
searchTerm=(mut searchTerm)
onChange=(action resetPagination)
placeholder="Search jobs..."}}
</div>
{{/if}}
<div class="column is-centered">

View File

@@ -6,6 +6,7 @@
{{search-box
data-test-allocations-search
searchTerm=(mut searchTerm)
onChange=(action resetPagination)
placeholder="Search allocations..."}}
</div>
</div>

View File

@@ -46,6 +46,7 @@
{{search-box
searchTerm=(mut searchTerm)
placeholder="Search allocations..."
onChange=(action resetPagination)
class="is-inline pull-right"
inputClass="is-compact"}}
</div>

View File

@@ -106,6 +106,24 @@ test('when there are jobs, but no matches for a search result, there is an empty
});
});
test('searching resets the current page', function(assert) {
server.createList('job', JobsList.pageSize + 1, { createAllocations: false });
JobsList.visit();
andThen(() => {
JobsList.nextPage();
});
andThen(() => {
assert.equal(currentURL(), '/jobs?page=2', 'Page query param captures page=2');
JobsList.search('foobar');
});
andThen(() => {
assert.equal(currentURL(), '/jobs?search=foobar', 'No page query param');
});
});
test('when the namespace query param is set, only matching jobs are shown and the namespace value is forwarded to app state', function(assert) {
server.createList('namespace', 2);
const job1 = server.create('job', { namespaceId: server.db.namespaces[0].id });

View File

@@ -31,6 +31,9 @@ export default create({
clickName: clickable('[data-test-job-name] a'),
}),
nextPage: clickable('[data-test-pager="next"]'),
prevPage: clickable('[data-test-pager="prev"]'),
isEmpty: isPresent('[data-test-empty-jobs-list]'),
emptyState: {
headline: text('[data-test-empty-jobs-list-headline]'),

View File

@@ -176,3 +176,32 @@ test('each search mode has independent search props', function(assert) {
'Canada is not matched by the regex because only id is looked at for regex search'
);
});
test('the resetPagination method is a no-op', function(assert) {
const subject = this.subject();
assert.strictEqual(subject.get('currentPage'), undefined, 'No currentPage value set');
subject.resetPagination();
assert.strictEqual(subject.get('currentPage'), undefined, 'Still no currentPage value set');
});
moduleFor('mixin:searchable', 'Unit | Mixin | Searchable (with pagination)', {
subject() {
const SearchablePaginatedObject = EmberObject.extend(Searchable, {
source: null,
searchProps: computed(() => ['id', 'name']),
listToSearch: alias('source'),
currentPage: 1,
});
this.register('test-container:searchable-paginated-object', SearchablePaginatedObject);
return getOwner(this).lookup('test-container:searchable-paginated-object');
},
});
test('the resetPagination method sets the currentPage to 1', function(assert) {
const subject = this.subject();
subject.set('currentPage', 5);
assert.equal(subject.get('currentPage'), 5, 'Current page is something other than 1');
subject.resetPagination();
assert.equal(subject.get('currentPage'), 1, 'Current page gets reset to 1');
});