mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-25 19:48:50 +03:00
Memoized member stats with expiration
no issue - added a `member-stats` service to keep member stats state outside of the chart component's lifecycle - returns memoized member stats when fetching if the query hasn't changed and the data is less than a minute old - reduces potentially heavy network requests when quickly navigating between members list and other screens
This commit is contained in:
parent
b7b6c4b1b7
commit
86702ed949
@ -7,7 +7,7 @@ import {task} from 'ember-concurrency';
|
|||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
ajax: service(),
|
ajax: service(),
|
||||||
ghostPaths: service(),
|
membersStats: service(),
|
||||||
|
|
||||||
// public attrs
|
// public attrs
|
||||||
nightShift: false,
|
nightShift: false,
|
||||||
@ -63,8 +63,7 @@ export default Component.extend({
|
|||||||
// Tasks -------------------------------------------------------------------
|
// Tasks -------------------------------------------------------------------
|
||||||
|
|
||||||
fetchStatsTask: task(function* () {
|
fetchStatsTask: task(function* () {
|
||||||
let statsUrl = this.ghostPaths.url.api('members/stats');
|
let stats = yield this.membersStats.fetch({days: this.selectedRange.days});
|
||||||
let stats = yield this.ajax.request(statsUrl, {data: {days: this.selectedRange.days}});
|
|
||||||
|
|
||||||
this.set('stats', stats);
|
this.set('stats', stats);
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||||
import {alias} from '@ember/object/computed';
|
import {alias} from '@ember/object/computed';
|
||||||
|
import {inject as service} from '@ember/service';
|
||||||
import {task} from 'ember-concurrency';
|
import {task} from 'ember-concurrency';
|
||||||
|
|
||||||
export default ModalComponent.extend({
|
export default ModalComponent.extend({
|
||||||
|
membersStats: service(),
|
||||||
|
|
||||||
// Allowed actions
|
// Allowed actions
|
||||||
confirm: () => {},
|
confirm: () => {},
|
||||||
|
|
||||||
@ -17,6 +20,7 @@ export default ModalComponent.extend({
|
|||||||
deleteMember: task(function* () {
|
deleteMember: task(function* () {
|
||||||
try {
|
try {
|
||||||
yield this.confirm();
|
yield this.confirm();
|
||||||
|
this.membersStats.invalidate();
|
||||||
} finally {
|
} finally {
|
||||||
this.send('closeModal');
|
this.send('closeModal');
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||||
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
||||||
import {computed} from '@ember/object';
|
import {computed} from '@ember/object';
|
||||||
|
import {inject as service} from '@ember/service';
|
||||||
|
|
||||||
export default ModalComponent.extend({
|
export default ModalComponent.extend({
|
||||||
|
membersStats: service(),
|
||||||
|
|
||||||
labelText: 'Select or drag-and-drop a CSV File',
|
labelText: 'Select or drag-and-drop a CSV File',
|
||||||
|
|
||||||
response: null,
|
response: null,
|
||||||
@ -26,6 +29,7 @@ export default ModalComponent.extend({
|
|||||||
|
|
||||||
uploadSuccess(response) {
|
uploadSuccess(response) {
|
||||||
this.set('response', response.meta.stats);
|
this.set('response', response.meta.stats);
|
||||||
|
this.membersStats.invalidate();
|
||||||
// invoke the passed in confirm action
|
// invoke the passed in confirm action
|
||||||
this.confirm();
|
this.confirm();
|
||||||
},
|
},
|
||||||
|
@ -13,6 +13,7 @@ export default class MemberController extends Controller {
|
|||||||
@controller members;
|
@controller members;
|
||||||
@service session;
|
@service session;
|
||||||
@service dropdown;
|
@service dropdown;
|
||||||
|
@service membersStats;
|
||||||
@service notifications;
|
@service notifications;
|
||||||
@service router;
|
@service router;
|
||||||
@service store;
|
@service store;
|
||||||
@ -66,6 +67,7 @@ export default class MemberController extends Controller {
|
|||||||
@action
|
@action
|
||||||
deleteMember() {
|
deleteMember() {
|
||||||
return this.member.destroyRecord().then(() => {
|
return this.member.destroyRecord().then(() => {
|
||||||
|
this.membersStats.invalidate();
|
||||||
return this.transitionToRoute('members');
|
return this.transitionToRoute('members');
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
return this.notifications.showAPIError(error, {key: 'member.delete'});
|
return this.notifications.showAPIError(error, {key: 'member.delete'});
|
||||||
@ -114,6 +116,10 @@ export default class MemberController extends Controller {
|
|||||||
let scratchProps = scratchMember.getProperties(SCRATCH_PROPS);
|
let scratchProps = scratchMember.getProperties(SCRATCH_PROPS);
|
||||||
member.setProperties(scratchProps);
|
member.setProperties(scratchProps);
|
||||||
|
|
||||||
|
if (!member.isNew) {
|
||||||
|
this.membersStats.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield member.save();
|
yield member.save();
|
||||||
member.updateLabels();
|
member.updateLabels();
|
||||||
|
33
ghost/admin/app/services/members-stats.js
Normal file
33
ghost/admin/app/services/members-stats.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import Service from '@ember/service';
|
||||||
|
import {inject as service} from '@ember/service';
|
||||||
|
import {tracked} from '@glimmer/tracking';
|
||||||
|
|
||||||
|
export default class MembersStatsService extends Service {
|
||||||
|
@service ajax;
|
||||||
|
@service ghostPaths;
|
||||||
|
|
||||||
|
@tracked stats = null;
|
||||||
|
|
||||||
|
fetch({days}) {
|
||||||
|
// return existing stats unless data is > 1 min old
|
||||||
|
let daysChanged = days === this._days;
|
||||||
|
let staleData = this._lastFetched - new Date() > 1 * 60 * 1000;
|
||||||
|
if (!this._forceRefresh && !daysChanged && !staleData) {
|
||||||
|
return Promise.resolve(this.stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._days = days;
|
||||||
|
this._lastFetched = new Date();
|
||||||
|
|
||||||
|
let statsUrl = this.ghostPaths.url.api('members/stats');
|
||||||
|
|
||||||
|
return this.ajax.request(statsUrl, {data: {days}}).then((stats) => {
|
||||||
|
this.stats = stats;
|
||||||
|
return stats;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate() {
|
||||||
|
this._forceRefresh = true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user