Ghost/ghost/admin/mirage/config/posts.js
Steve Larson c61c42ce1d
Improved performance loading posts & pages in admin (#20646)
ref 8ea1dfb
ref https://linear.app/tryghost/issue/ONC-111

* undid the reversion for the performance improvements
* built upon new tests for the posts list functionality in admin,
including right click actions
* added tests for pages view in Admin

This was reverted because it broke the Pages list view in Admin, which
is a thin extension of the Posts functionality in admin (route &
controller). That has been fixed and tests added.

This was originally reverted because the changes to improve loading
response times broke right click (bulk) actions in the posts list. This
was not caught because it turned out we had near-zero test coverage of
that part of the codebase. Test coverage has been expanded for the posts
list, and while not comprehensive, is a much better place for us to be
in.
2024-07-29 16:19:28 +00:00

141 lines
4.4 KiB
JavaScript

import moment from 'moment-timezone';
import {Response} from 'miragejs';
import {dasherize} from '@ember/string';
import {extractFilterParam, paginateModelCollection} from '../utils';
import {isBlank, isEmpty} from '@ember/utils';
// NOTE: mirage requires Model objects when saving relationships, however the
// `attrs` on POST/PUT requests will contain POJOs for authors and tags so we
// need to replace them
function extractAuthors(postAttrs, users) {
return postAttrs.authors.map(author => users.find(author.id));
}
function extractTags(postAttrs, tags) {
return postAttrs.tags.map((requestTag) => {
let tag = tags.find(requestTag.id);
if (!tag) {
tag = tag.create(requestTag);
}
return tag;
});
}
export function getPosts({posts}, {queryParams}) {
let {filter, page, limit} = queryParams;
page = +page || 1;
limit = +limit || 15;
let statusFilter = extractFilterParam('status', filter);
let authorsFilter = extractFilterParam('authors', filter);
let visibilityFilter = extractFilterParam('visibility', filter);
let collection = posts.all().filter((post) => {
let matchesStatus = true;
let matchesAuthors = true;
let matchesVisibility = true;
if (!isEmpty(statusFilter)) {
matchesStatus = statusFilter.includes(post.status);
}
if (!isEmpty(authorsFilter)) {
matchesAuthors = authorsFilter.includes(post.authors.models[0].slug);
}
if (!isEmpty(visibilityFilter)) {
matchesVisibility = visibilityFilter.includes(post.visibility);
}
return matchesStatus && matchesAuthors && matchesVisibility;
});
return paginateModelCollection('posts', collection, page, limit);
}
export default function mockPosts(server) {
server.post('/posts', function ({posts, users, tags}) {
let attrs = this.normalizedRequestAttrs();
attrs.authors = extractAuthors(attrs, users);
attrs.tags = extractTags(attrs, tags);
if (isBlank(attrs.slug) && !isBlank(attrs.title)) {
attrs.slug = dasherize(attrs.title);
}
return posts.create(attrs);
});
server.get('/posts/', getPosts);
server.get('/posts/:id/', function ({posts}, {params}) {
let {id} = params;
let post = posts.find(id);
return post || new Response(404, {}, {
errors: [{
type: 'NotFoundError',
message: 'Post not found.'
}]
});
});
server.put('/posts/:id/', function ({newsletters, posts, users, tags}, {params, queryParams}) {
const attrs = this.normalizedRequestAttrs();
const post = posts.find(params.id);
attrs.authors = extractAuthors(attrs, users);
attrs.tags = extractTags(attrs, tags);
attrs.updatedAt = moment.utc().toDate();
if (queryParams.newsletter) {
const newsletter = newsletters.findBy({slug: queryParams.newsletter});
post.newsletter = newsletter;
post.save();
}
return post.update(attrs);
});
server.del('/posts/:id/');
server.del('/posts/', function ({posts}, {queryParams}) {
let ids = extractFilterParam('id', queryParams.filter);
posts.find(ids).destroy();
});
server.post('/posts/:id/copy/', function ({posts}, {params}) {
let post = posts.find(params.id);
let attrs = post.attrs;
return posts.create(attrs);
});
server.put('/posts/bulk/', function ({tags}, {requestBody}) {
const bulk = JSON.parse(requestBody).bulk;
const action = bulk.action;
// const ids = extractFilterParam('id', queryParams.filter);
if (action === 'addTag') {
// create tag so we have an id from the server
const newTags = bulk.meta.tags;
// check applied tags to see if any new ones should be created
newTags.forEach((tag) => {
if (!tag.id) {
tags.create(tag);
}
});
// TODO: update the actual posts in the mock db if wanting to write tests where we navigate around (refresh model)
// const postsToUpdate = posts.find(ids);
// getting the posts is fine, but within this we CANNOT manipulate them (???) not even iterate with .forEach
}
});
}