Skip to content

Commit 2f57da8

Browse files
committed
Removed all-tags load when accessing tags screen
ref https://linear.app/ghost/issue/PROD-1605/ - switched from performing an all-tags fetch with a `peekAll` for the tags screen model to using `InfinityModel` - set up to cache for 5 minutes so there are no unnecessary queries when switching between filters or to/from the create/edit tag screens - updated the `vertical-collection` usage to trigger the infinity model to load more when the end is reached - updated tags filter to exclude deleted entries so there's no need to refresh after deleting a tag - updated new tag controller to push the tag onto the infinity model (shared instance stored on the `tags-manager` service) so there's no need to refresh after adding a tag
1 parent 2e926b6 commit 2f57da8

File tree

5 files changed

+56
-17
lines changed

5 files changed

+56
-17
lines changed

ghost/admin/app/controllers/tag.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export default class TagController extends Controller {
99
@service modals;
1010
@service notifications;
1111
@service router;
12+
@service tagsManager;
13+
1214
@inject config;
1315

1416
get tag() {
@@ -45,6 +47,8 @@ export default class TagController extends Controller {
4547
}
4648
yield tag.save();
4749

50+
this.tagsManager.tagsScreenInfinityModel?.pushObjects([tag]);
51+
4852
// replace 'new' route with 'tag' route
4953
this.replaceRoute('tag', tag);
5054

ghost/admin/app/controllers/tags.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {inject as service} from '@ember/service';
44
import {tracked} from '@glimmer/tracking';
55

66
export default class TagsController extends Controller {
7+
@service infinity;
78
@service router;
9+
@service tagsManager;
810

911
queryParams = ['type'];
1012
@tracked type = 'public';
@@ -15,15 +17,12 @@ export default class TagsController extends Controller {
1517

1618
get filteredTags() {
1719
return this.tags.filter((tag) => {
18-
return (!tag.isNew && (!this.type || tag.visibility === this.type));
20+
return (!tag.isNew && !tag.isDestroyed && !tag.isDestroying && !tag.isDeleted && (!this.type || tag.visibility === this.type));
1921
});
2022
}
2123

2224
get sortedTags() {
23-
return this.filteredTags.sort((tagA, tagB) => {
24-
// ignorePunctuation means the # in internal tag names is ignored
25-
return tagA.name.localeCompare(tagB.name, undefined, {ignorePunctuation: true});
26-
});
25+
return this.tagsManager.sortTags(this.filteredTags);
2726
}
2827

2928
@action
@@ -35,4 +34,9 @@ export default class TagsController extends Controller {
3534
newTag() {
3635
this.router.transitionTo('tag.new');
3736
}
37+
38+
@action
39+
loadMoreTags() {
40+
this.infinity.infinityLoad(this.model);
41+
}
3842
}

ghost/admin/app/routes/tags.js

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2+
import {inject as service} from '@ember/service';
3+
4+
const CACHE_TIME = 1000 * 60 * 5; // 5 minutes
25

36
export default class TagsRoute extends AuthenticatedRoute {
7+
@service infinity;
8+
@service tagsManager;
9+
410
queryParams = {
511
type: {
612
refreshModel: true,
@@ -17,22 +23,37 @@ export default class TagsRoute extends AuthenticatedRoute {
1723
}
1824
}
1925

20-
// set model to a live array so all tags are shown and created/deleted tags
21-
// are automatically added/removed. Also load all tags in the background,
22-
// pausing to show the loading spinner if no tags have been loaded yet
23-
model() {
24-
let promise = this.store.query('tag', {limit: 'all', include: 'count.posts'});
25-
let tags = this.store.peekAll('tag');
26-
if (this.store.peekAll('tag').get('length') === 0) {
27-
return promise.then(() => tags);
28-
} else {
29-
return tags;
30-
}
26+
model(params) {
27+
const filterParams = {
28+
visibility: params.type
29+
};
30+
31+
const paginationParams = {
32+
perPage: 100,
33+
perPageParam: 'limit',
34+
totalPagesParam: 'meta.pagination.pages',
35+
order: 'name asc',
36+
include: 'count.posts'
37+
};
38+
39+
this.tagsManager.tagsScreenInfinityModel = this.infinity.model('tag', {
40+
...paginationParams,
41+
filter: this._filterString({...filterParams}),
42+
infinityCache: CACHE_TIME
43+
});
44+
45+
return this.tagsManager.tagsScreenInfinityModel;
3146
}
3247

3348
buildRouteInfoMetadata() {
3449
return {
3550
titleToken: 'Tags'
3651
};
3752
}
53+
54+
_filterString(filter) {
55+
return Object.entries(filter).map(([key, value]) => {
56+
return `${key}:${value}`;
57+
}).join(',');
58+
}
3859
}

ghost/admin/app/services/tags-manager.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import Service, {inject as service} from '@ember/service';
22
import {task, timeout} from 'ember-concurrency';
3+
import {tracked} from '@glimmer/tracking';
34

45
export default class TagsManagerService extends Service {
56
@service store;
67

8+
@tracked tagsScreenInfinityModel = null;
9+
710
_loadedTags = this.store.peekAll('tag');
811

912
get loadedTags() {

ghost/admin/app/templates/tags.hbs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
<div class="gh-list-header gh-list-cellwidth-10">No. of posts</div>
2020
<div class="gh-list-header gh-list-cellwidth-10"></div>
2121
</li>
22-
<VerticalCollection @items={{this.sortedTags}} @key="id" @containerSelector=".gh-main" @estimateHeight={{60}} @bufferSize={{20}} as |tag|>
22+
<VerticalCollection
23+
@items={{this.sortedTags}}
24+
@key="id"
25+
@containerSelector=".gh-main"
26+
@estimateHeight={{60}}
27+
@bufferSize={{20}}
28+
@lastReached={{this.loadMoreTags}}
29+
as |tag|>
2330
<Tags::ListItem @tag={{tag}} data-test-tag={{tag.id}} />
2431
</VerticalCollection>
2532
{{else}}

0 commit comments

Comments
 (0)