0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

🐛 Fixed infinite scroll on the team screen (#1095)

closes https://github.com/TryGhost/Ghost/issues/10307
- removed infinite scroll from the team screen
- adjusted team screen behaviour to pull from the local cache and update in the background to speed up navigation to the screen
- use `{{vertical-collection}}` to render the users list for faster initial render with many users
This commit is contained in:
Kevin Ansfield 2019-01-14 14:50:30 +00:00 committed by GitHub
parent 5e3de1c333
commit 434e8ba2f7
4 changed files with 77 additions and 78 deletions

View file

@ -1,18 +1,17 @@
/* eslint-disable ghost/ember/alias-model-in-controller */
import Controller from '@ember/controller';
import RSVP from 'rsvp';
import {alias, sort} from '@ember/object/computed';
import {computed} from '@ember/object';
import {inject as service} from '@ember/service';
import {sort} from '@ember/object/computed';
import {task} from 'ember-concurrency';
export default Controller.extend({
session: service(),
store: service(),
showInviteUserModal: false,
activeUsers: null,
suspendedUsers: null,
invites: null,
inviteOrder: null,
userOrder: null,
@ -22,17 +21,67 @@ export default Controller.extend({
this.userOrder = ['name', 'email'];
},
currentUser: alias('model'),
sortedInvites: sort('filteredInvites', 'inviteOrder'),
sortedActiveUsers: sort('activeUsers', 'userOrder'),
sortedSuspendedUsers: sort('suspendedUsers', 'userOrder'),
invites: computed(function () {
return this.store.peekAll('invite');
}),
filteredInvites: computed('invites.@each.isNew', function () {
return this.get('invites').filterBy('isNew', false);
return this.invites.filterBy('isNew', false);
}),
allUsers: computed(function () {
return this.store.peekAll('user');
}),
activeUsers: computed('allUsers.@each.status', function () {
return this.allUsers.filter((user) => {
return user.status !== 'inactive';
});
}),
suspendedUsers: computed('allUsers.@each.status', function () {
return this.allUsers.filter((user) => {
return user.status === 'inactive';
});
}),
actions: {
toggleInviteUserModal() {
this.toggleProperty('showInviteUserModal');
}
}
},
backgroundUpdate: task(function* () {
let users = this.fetchUsers.perform();
let invites = this.fetchInvites.perform();
let roles = this.fetchRoles.perform();
try {
yield RSVP.all([users, invites, roles]);
} catch (error) {
this.send('error', error);
}
}),
fetchUsers: task(function* () {
yield this.store.query('user', {limit: 'all'});
}),
fetchInvites: task(function* () {
if (this.currentUser.isAuthorOrContributor) {
return;
}
return yield this.store.query('invite', {limit: 'all'});
}),
fetchRoles: task(function* () {
return yield this.store.findAll('role');
})
});

View file

@ -1,58 +1,27 @@
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import CurrentUserSettings from 'ghost-admin/mixins/current-user-settings';
import RSVP from 'rsvp';
import styleBody from 'ghost-admin/mixins/style-body';
import {inject as service} from '@ember/service';
export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
infinity: service(),
session: service(),
titleToken: 'Team',
classNames: ['view-team'],
modelPath: 'controller.activeUsers',
perPage: 15,
model() {
return this.get('session.user').then((user) => {
let modelPath = this.get('modelPath');
let perPage = this.get('perPage');
let modelPromises = {
activeUsers: this.infinity.model('user', {
modelPath,
perPage,
filter: 'status:-inactive',
startingPage: 1,
perPageParam: 'limit',
totalPagesParam: 'meta.pagination.pages'
})
};
// authors do not have permission to hit the invites or suspended users endpoint
if (!user.get('isAuthorOrContributor')) {
modelPromises.invites = this.store.query('invite', {limit: 'all'})
.then(() => this.store.peekAll('invite'));
// fetch suspended users separately so that infinite scroll still works
modelPromises.suspendedUsers = this.store.query('user', {limit: 'all', filter: 'status:inactive'});
}
// we need to load the roles into ember cache
// invites return role_id only and we do not offer a /role/:id endpoint
modelPromises.roles = this.get('store').query('role', {});
return RSVP.hash(modelPromises);
});
return this.session.user;
},
setupController(controller, models) {
controller.setProperties(models);
setupController(controller) {
this._super(...arguments);
controller.backgroundUpdate.perform();
},
actions: {
reload() {
this.refresh();
this.controller.backgroundUpdate.perform();
}
}
});

View file

@ -1,15 +0,0 @@
<section class="gh-canvas">
<header class="gh-canvas-header">
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
{{!-- Do not show Invite user button to authors --}}
{{#unless session.user.isAuthorOrContributor}}
<section class="view-actions">
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
</section>
{{/unless}}
</header>
<div class="gh-content">
{{gh-loading-spinner}}
</div>
</section>

View file

@ -2,7 +2,7 @@
<header class="gh-canvas-header">
<h2 class="gh-canvas-title" data-test-screen-title>Team members</h2>
{{!-- Do not show Invite user button to authors --}}
{{#unless session.user.isAuthorOrContributor}}
{{#unless currentUser.isAuthorOrContributor}}
<section class="view-actions">
<button class="gh-btn gh-btn-green" {{action "toggleInviteUserModal"}} ><span>Invite People</span></button>
</section>
@ -16,9 +16,8 @@
{{/if}}
<section class="gh-team">
{{!-- Show invited users to everyone except authors --}}
{{#unless session.user.isAuthorOrContributor}}
{{#unless currentUser.isAuthorOrContributor}}
{{#if invites}}
<section class="apps-grid-container gh-invited-users" data-test-invited-users>
<span class="apps-grid-title">Invited users</span>
@ -75,32 +74,29 @@
<section class="apps-grid-container gh-active-users" data-test-active-users>
<span class="apps-grid-title">Active users</span>
<div class="apps-grid">
{{!-- For authors/contributors only show their own user --}}
{{#if session.user.isAuthorOrContributor}}
{{#with session.user as |user|}}
{{#gh-user-active user=user as |component|}}
{{gh-user-list-item user=user component=component}}
{{/gh-user-active}}
{{/with}}
{{!-- For authors/contributors, only show their own user --}}
{{#if currentUser.isAuthorOrContributor}}
{{#gh-user-active user=currentUser as |component|}}
{{gh-user-list-item user=currentUser component=component}}
{{/gh-user-active}}
{{else}}
{{#each sortedActiveUsers key="id" as |user|}}
{{#vertical-collection sortedActiveUsers
key="id"
containerSelector=".gh-main"
estimateHeight=75
as |user|
}}
{{#gh-user-active user=user as |component|}}
{{gh-user-list-item user=user component=component}}
{{/gh-user-active}}
{{/each}}
{{/vertical-collection}}
{{/if}}
</div>
</section>
{{gh-infinity-loader
infinityModel=activeUsers
scrollable=".gh-main"
triggerOffset=500}}
</section>
{{!-- Don't show if we have no suspended users or logged in as an author --}}
{{#if (and suspendedUsers (not session.user.isAuthorOrContributor))}}
{{#if (and suspendedUsers (not currentUser.isAuthorOrContributor))}}
<section class="apps-grid-container gh-active-users" data-test-suspended-users>
<span class="apps-grid-title">Suspended users</span>
<div class="apps-grid">