mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
🐛 Fixed Admin search sometimes stalling on first query (#20143)
closes https://linear.app/tryghost/issue/MOM-103 - the `yield waitForProperty(...)` call that was supposed to return once the content refresh occurred never reached a valid state so the first search query (or any later query) where a content refresh occurred would never resolve causing search to look like it had stalled - switched to waiting for the last running task to resolve instead which does the same as the previous code intended - exported the `getPosts` request handler function so in mirage config so we can re-use it with different timing on a per-case basis
This commit is contained in:
parent
f34c33f330
commit
0f482907e1
3 changed files with 48 additions and 22 deletions
|
@ -3,7 +3,7 @@ import Service from '@ember/service';
|
||||||
import {isBlank, isEmpty} from '@ember/utils';
|
import {isBlank, isEmpty} from '@ember/utils';
|
||||||
import {pluralize} from 'ember-inflector';
|
import {pluralize} from 'ember-inflector';
|
||||||
import {inject as service} from '@ember/service';
|
import {inject as service} from '@ember/service';
|
||||||
import {task, timeout, waitForProperty} from 'ember-concurrency';
|
import {task, timeout} from 'ember-concurrency';
|
||||||
|
|
||||||
export default class SearchService extends Service {
|
export default class SearchService extends Service {
|
||||||
@service ajax;
|
@service ajax;
|
||||||
|
@ -59,7 +59,7 @@ export default class SearchService extends Service {
|
||||||
|
|
||||||
// wait for any on-going refresh to finish
|
// wait for any on-going refresh to finish
|
||||||
if (this.refreshContentTask.isRunning) {
|
if (this.refreshContentTask.isRunning) {
|
||||||
yield waitForProperty(this, 'refreshContentTask.isIdle');
|
yield this.refreshContentTask.lastRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchResult = this._searchContent(term);
|
const searchResult = this._searchContent(term);
|
||||||
|
|
|
@ -23,6 +23,28 @@ function extractTags(postAttrs, tags) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: handle authors filter
|
||||||
|
export function getPosts({posts}, {queryParams}) {
|
||||||
|
let {filter, page, limit} = queryParams;
|
||||||
|
|
||||||
|
page = +page || 1;
|
||||||
|
limit = +limit || 15;
|
||||||
|
|
||||||
|
let statusFilter = extractFilterParam('status', filter);
|
||||||
|
|
||||||
|
let collection = posts.all().filter((post) => {
|
||||||
|
let matchesStatus = true;
|
||||||
|
|
||||||
|
if (!isEmpty(statusFilter)) {
|
||||||
|
matchesStatus = statusFilter.includes(post.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchesStatus;
|
||||||
|
});
|
||||||
|
|
||||||
|
return paginateModelCollection('posts', collection, page, limit);
|
||||||
|
}
|
||||||
|
|
||||||
export default function mockPosts(server) {
|
export default function mockPosts(server) {
|
||||||
server.post('/posts', function ({posts, users, tags}) {
|
server.post('/posts', function ({posts, users, tags}) {
|
||||||
let attrs = this.normalizedRequestAttrs();
|
let attrs = this.normalizedRequestAttrs();
|
||||||
|
@ -38,26 +60,7 @@ export default function mockPosts(server) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: handle authors filter
|
// TODO: handle authors filter
|
||||||
server.get('/posts/', function ({posts}, {queryParams}) {
|
server.get('/posts/', getPosts);
|
||||||
let {filter, page, limit} = queryParams;
|
|
||||||
|
|
||||||
page = +page || 1;
|
|
||||||
limit = +limit || 15;
|
|
||||||
|
|
||||||
let statusFilter = extractFilterParam('status', filter);
|
|
||||||
|
|
||||||
let collection = posts.all().filter((post) => {
|
|
||||||
let matchesStatus = true;
|
|
||||||
|
|
||||||
if (!isEmpty(statusFilter)) {
|
|
||||||
matchesStatus = statusFilter.includes(post.status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchesStatus;
|
|
||||||
});
|
|
||||||
|
|
||||||
return paginateModelCollection('posts', collection, page, limit);
|
|
||||||
});
|
|
||||||
|
|
||||||
server.get('/posts/:id/', function ({posts}, {params}) {
|
server.get('/posts/:id/', function ({posts}, {params}) {
|
||||||
let {id} = params;
|
let {id} = params;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {authenticateSession} from 'ember-simple-auth/test-support';
|
||||||
import {click, currentURL, find, findAll, triggerKeyEvent, visit} from '@ember/test-helpers';
|
import {click, currentURL, find, findAll, triggerKeyEvent, visit} from '@ember/test-helpers';
|
||||||
import {describe, it} from 'mocha';
|
import {describe, it} from 'mocha';
|
||||||
import {expect} from 'chai';
|
import {expect} from 'chai';
|
||||||
|
import {getPosts} from '../../mirage/config/posts';
|
||||||
import {setupApplicationTest} from 'ember-mocha';
|
import {setupApplicationTest} from 'ember-mocha';
|
||||||
import {setupMirage} from 'ember-cli-mirage/test-support';
|
import {setupMirage} from 'ember-cli-mirage/test-support';
|
||||||
import {typeInSearch} from 'ember-power-select/test-support/helpers';
|
import {typeInSearch} from 'ember-power-select/test-support/helpers';
|
||||||
|
@ -142,4 +143,26 @@ describe('Acceptance: Search', function () {
|
||||||
await typeInSearch('x');
|
await typeInSearch('x');
|
||||||
expect(find('.ember-power-select-option--no-matches-message'), 'no results message').to.contain.text('No results found');
|
expect(find('.ember-power-select-option--no-matches-message'), 'no results message').to.contain.text('No results found');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://linear.app/tryghost/issue/MOM-103/search-stalls-on-query-when-refresh-occurs
|
||||||
|
it('handles refresh on first search being slow', async function () {
|
||||||
|
this.server.get('/posts/', getPosts, {timing: 200});
|
||||||
|
|
||||||
|
await visit('/dashboard');
|
||||||
|
await click('[data-test-button="search"]');
|
||||||
|
await typeInSearch('first'); // search is not case sensitive
|
||||||
|
|
||||||
|
// all groups are present
|
||||||
|
const groupNames = findAll('.ember-power-select-group-name');
|
||||||
|
expect(groupNames, 'group names').to.have.length(4);
|
||||||
|
expect(groupNames.map(el => el.textContent.trim())).to.deep.equal(['Posts', 'Pages', 'Staff', 'Tags']);
|
||||||
|
|
||||||
|
// correct results are found
|
||||||
|
const options = findAll('.ember-power-select-option');
|
||||||
|
expect(options, 'number of search results').to.have.length(4);
|
||||||
|
expect(options.map(el => el.textContent.trim())).to.deep.equal(['First post', 'First page', 'First user', 'First tag']);
|
||||||
|
|
||||||
|
// first item is selected
|
||||||
|
expect(options[0]).to.have.attribute('aria-current', 'true');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue