From ff33eb978b5839bcf3efa0968f34768c46f7eca7 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Thu, 28 May 2020 10:15:17 +0100 Subject: [PATCH] Added server-side search to new members screen (#1582) requires https://github.com/TryGhost/Ghost/pull/11854 - ties the search input on the members screen to a `?search` query param, debounced at 250ms to avoid unnecessary API requests and UI churn - updated the members route's `model` hook to pass through the search param in the API request query parameters --- ghost/admin/app/controllers/members.js | 23 +++++++++++++++++-- ghost/admin/app/helpers/reset-query-params.js | 3 ++- ghost/admin/app/routes/members.js | 13 ++++++++--- ghost/admin/app/templates/members.hbs | 3 +-- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/ghost/admin/app/controllers/members.js b/ghost/admin/app/controllers/members.js index 5a810cb96b..fdd2200b73 100644 --- a/ghost/admin/app/controllers/members.js +++ b/ghost/admin/app/controllers/members.js @@ -7,17 +7,19 @@ import {formatNumber} from 'ghost-admin/helpers/format-number'; import {pluralize} from 'ember-inflector'; import {inject as service} from '@ember/service'; import {task} from 'ember-concurrency-decorators'; +import {timeout} from 'ember-concurrency'; import {tracked} from '@glimmer/tracking'; export default class MembersController extends Controller { @service feature; @service store; - queryParams = ['label']; + queryParams = ['label', {searchParam: 'search'}]; @alias('model') members; @tracked searchText = ''; + @tracked searchParam = ''; @tracked label = null; @tracked modalLabel = null; @tracked showLabelModal = false; @@ -56,7 +58,7 @@ export default class MembersController extends Controller { } get showingAll() { - return !this.searchText && !this.label; + return !this.searchParam && !this.label; } get availableLabels() { @@ -88,6 +90,11 @@ export default class MembersController extends Controller { // Actions ----------------------------------------------------------------- + @action + search(e) { + this.searchTask.perform(e.target.value); + } + @action exportData() { let exportUrl = ghostPaths().url.api('members/csv'); @@ -141,6 +148,12 @@ export default class MembersController extends Controller { // Tasks ------------------------------------------------------------------- + @task({restartable: true}) + *searchTask(query) { + yield timeout(250); // debounce + this.searchParam = query; + } + @task *fetchLabelsTask() { if (!this._hasLoadedLabels) { @@ -149,4 +162,10 @@ export default class MembersController extends Controller { }); } } + + // Internal ---------------------------------------------------------------- + + resetSearch() { + this.searchText = ''; + } } diff --git a/ghost/admin/app/helpers/reset-query-params.js b/ghost/admin/app/helpers/reset-query-params.js index e4b94f0328..95ae2966d7 100644 --- a/ghost/admin/app/helpers/reset-query-params.js +++ b/ghost/admin/app/helpers/reset-query-params.js @@ -14,7 +14,8 @@ export const DEFAULT_QUERY_PARAMS = { order: null }, 'members.index': { - label: null + label: null, + searchParam: '' } }; diff --git a/ghost/admin/app/routes/members.js b/ghost/admin/app/routes/members.js index 48fa94573c..b7f1c6a13a 100644 --- a/ghost/admin/app/routes/members.js +++ b/ghost/admin/app/routes/members.js @@ -8,7 +8,8 @@ export default class MembersRoute extends AuthenticatedRoute { @service store; queryParams = { - label: {refreshModel: true} + label: {refreshModel: true}, + searchParam: {refreshModel: true, replace: true} }; // redirect to posts screen if: @@ -24,12 +25,17 @@ export default class MembersRoute extends AuthenticatedRoute { } model(params) { + if (!params.searchParam) { + this.controllerFor('members').resetSearch(); + } + // use a fixed created_at date so that subsequent pages have a consistent index let startDate = new Date(); // bypass the stale data shortcut if params change - let forceReload = params.label !== this._lastLabel; + let forceReload = params.label !== this._lastLabel || params.searchParam !== this._lastSearchParam; this._lastLabel = params.label; + this._lastSearchParam = params.searchParam; // unless we have a forced reload, do not re-fetch the members list unless it's more than a minute old // keeps navigation between list->details->list snappy @@ -46,7 +52,8 @@ export default class MembersRoute extends AuthenticatedRoute { limit: range.length, page: range.start / range.length, order: 'created_at desc', - filter: `${labelFilter}created_at:<='${moment.utc(this._startDate).format('YYYY-MM-DD HH:mm:ss')}'` + filter: `${labelFilter}created_at:<='${moment.utc(this._startDate).format('YYYY-MM-DD HH:mm:ss')}'`, + search: params.searchParam }, query); return this.store.query('member', query).then((result) => { diff --git a/ghost/admin/app/templates/members.hbs b/ghost/admin/app/templates/members.hbs index 62d9c88833..612504a7b2 100644 --- a/ghost/admin/app/templates/members.hbs +++ b/ghost/admin/app/templates/members.hbs @@ -13,9 +13,8 @@ {{svg-jar "search" class="gh-input-search-icon"}}