Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
🐛 Fixed infinite scroll on the team screen (#1095)
Browse files Browse the repository at this point in the history
closes TryGhost/Ghost#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
  • Loading branch information
kevinansfield committed Jan 14, 2019
1 parent bccd9ea commit 782ff71
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 78 deletions.
63 changes: 56 additions & 7 deletions app/controllers/team/index.js
@@ -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,

Expand All @@ -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');
})
});
43 changes: 6 additions & 37 deletions app/routes/team/index.js
@@ -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();
}
}
});
15 changes: 0 additions & 15 deletions app/templates/team/index-loading.hbs

This file was deleted.

34 changes: 15 additions & 19 deletions app/templates/team/index.hbs
Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -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">
Expand Down

0 comments on commit 782ff71

Please sign in to comment.