mirror of
https://github.com/flarum/core.git
synced 2025-08-05 07:57:46 +02:00
perf(likes): limit likes
relationship results (#3781)
* perf(core,mentions): limit `mentionedBy` post relation results Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * Apply fixes from StyleCI * chore: use a static property to allow customization Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: use a static property to allow customization Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: include count in show post endpoint Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: consistent locale key format Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * chore: forgot to delete `FilterVisiblePosts` Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * test: `mentionedByCount` must not include invisible posts to actor Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * fix: visibility scoping on `mentionedByCount` Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * fix: `loadAggregates` conflicts with visibility scopers Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * Apply fixes from StyleCI * chore: phpstan Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * perf(likes): limit `likes` relationship results Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * Apply fixes from StyleCI * chore: simplify Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * test: `likesCount` is as expected Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> * Apply fixes from StyleCI --------- Signed-off-by: Sami Mazouz <sychocouldy@gmail.com> Co-authored-by: StyleCI Bot <bot@styleci.io> Co-authored-by: IanM <16573496+imorland@users.noreply.github.com>
This commit is contained in:
9
extensions/likes/js/src/@types/shims.d.ts
vendored
Normal file
9
extensions/likes/js/src/@types/shims.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import Post from 'flarum/common/models/Post';
|
||||
import User from 'flarum/common/models/User';
|
||||
|
||||
declare module 'flarum/common/models/Post' {
|
||||
export default interface Post {
|
||||
likes(): User[];
|
||||
likesCount(): number;
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@ import username from 'flarum/common/helpers/username';
|
||||
import icon from 'flarum/common/helpers/icon';
|
||||
|
||||
import PostLikesModal from './components/PostLikesModal';
|
||||
import Button from '@flarum/core/src/common/components/Button';
|
||||
|
||||
export default function () {
|
||||
extend(CommentPost.prototype, 'footerItems', function (items) {
|
||||
@@ -15,7 +16,7 @@ export default function () {
|
||||
|
||||
if (likes && likes.length) {
|
||||
const limit = 4;
|
||||
const overLimit = likes.length > limit;
|
||||
const overLimit = post.likesCount() > limit;
|
||||
|
||||
// Construct a list of names of users who have liked this post. Make sure the
|
||||
// current user is first in the list, and cap a maximum of 4 items.
|
||||
@@ -34,19 +35,24 @@ export default function () {
|
||||
// others" name to the end of the list. Clicking on it will display a modal
|
||||
// with a full list of names.
|
||||
if (overLimit) {
|
||||
const count = likes.length - names.length;
|
||||
const count = post.likesCount() - names.length;
|
||||
const label = app.translator.trans('flarum-likes.forum.post.others_link', { count });
|
||||
|
||||
names.push(
|
||||
<a
|
||||
href="#"
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
app.modal.show(PostLikesModal, { post });
|
||||
}}
|
||||
>
|
||||
{app.translator.trans('flarum-likes.forum.post.others_link', { count })}
|
||||
</a>
|
||||
);
|
||||
if (app.forum.attribute('canSearchUsers')) {
|
||||
names.push(
|
||||
<Button
|
||||
className="Button Button--ua-reset Button--text"
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
app.modal.show(PostLikesModal, { post });
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
names.push(<span>{label}</span>);
|
||||
}
|
||||
}
|
||||
|
||||
items.add(
|
||||
|
@@ -1,31 +0,0 @@
|
||||
import app from 'flarum/forum/app';
|
||||
import Modal from 'flarum/common/components/Modal';
|
||||
import Link from 'flarum/common/components/Link';
|
||||
import avatar from 'flarum/common/helpers/avatar';
|
||||
import username from 'flarum/common/helpers/username';
|
||||
|
||||
export default class PostLikesModal extends Modal {
|
||||
className() {
|
||||
return 'PostLikesModal Modal--small';
|
||||
}
|
||||
|
||||
title() {
|
||||
return app.translator.trans('flarum-likes.forum.post_likes.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
return (
|
||||
<div className="Modal-body">
|
||||
<ul className="PostLikesModal-list">
|
||||
{this.attrs.post.likes().map((user) => (
|
||||
<li>
|
||||
<Link href={app.route.user(user)}>
|
||||
{avatar(user)} {username(user)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
72
extensions/likes/js/src/forum/components/PostLikesModal.tsx
Normal file
72
extensions/likes/js/src/forum/components/PostLikesModal.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import app from 'flarum/forum/app';
|
||||
import Modal from 'flarum/common/components/Modal';
|
||||
import Link from 'flarum/common/components/Link';
|
||||
import avatar from 'flarum/common/helpers/avatar';
|
||||
import username from 'flarum/common/helpers/username';
|
||||
import type { IInternalModalAttrs } from 'flarum/common/components/Modal';
|
||||
import type Post from 'flarum/common/models/Post';
|
||||
import type Mithril from 'mithril';
|
||||
import PostLikesModalState from '../states/PostLikesModalState';
|
||||
import Button from '@flarum/core/src/common/components/Button';
|
||||
import LoadingIndicator from '@flarum/core/src/common/components/LoadingIndicator';
|
||||
|
||||
export interface IPostLikesModalAttrs extends IInternalModalAttrs {
|
||||
post: Post;
|
||||
}
|
||||
|
||||
export default class PostLikesModal<CustomAttrs extends IPostLikesModalAttrs = IPostLikesModalAttrs> extends Modal<CustomAttrs, PostLikesModalState> {
|
||||
oninit(vnode: Mithril.VnodeDOM<CustomAttrs, this>) {
|
||||
super.oninit(vnode);
|
||||
|
||||
this.state = new PostLikesModalState({
|
||||
filter: {
|
||||
liked: this.attrs.post.id()!,
|
||||
},
|
||||
});
|
||||
|
||||
this.state.refresh();
|
||||
}
|
||||
|
||||
className() {
|
||||
return 'PostLikesModal Modal--small';
|
||||
}
|
||||
|
||||
title() {
|
||||
return app.translator.trans('flarum-likes.forum.post_likes.title');
|
||||
}
|
||||
|
||||
content() {
|
||||
return (
|
||||
<>
|
||||
<div className="Modal-body">
|
||||
{this.state.isInitialLoading() ? (
|
||||
<LoadingIndicator />
|
||||
) : (
|
||||
<ul className="PostLikesModal-list">
|
||||
{this.state.getPages().map((page) =>
|
||||
page.items.map((user) => (
|
||||
<li>
|
||||
<Link href={app.route.user(user)}>
|
||||
{avatar(user)} {username(user)}
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
{this.state.hasNext() ? (
|
||||
<div className="Modal-footer">
|
||||
<div className="Form Form--centered">
|
||||
<div className="Form-group">
|
||||
<Button className="Button Button--block" onclick={() => this.state.loadNext()} loading={this.state.isLoadingNext()}>
|
||||
{app.translator.trans('flarum-likes.forum.post_likes.load_more_button')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
@@ -9,5 +9,6 @@ export default [
|
||||
|
||||
new Extend.Model(Post) //
|
||||
.hasMany<User>('likes')
|
||||
.attribute<number>('likesCount')
|
||||
.attribute<boolean>('canLike'),
|
||||
];
|
||||
|
26
extensions/likes/js/src/forum/states/PostLikesModalState.ts
Normal file
26
extensions/likes/js/src/forum/states/PostLikesModalState.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import PaginatedListState, { PaginatedListParams } from '@flarum/core/src/common/states/PaginatedListState';
|
||||
import User from 'flarum/common/models/User';
|
||||
|
||||
export interface PostLikesModalListParams extends PaginatedListParams {
|
||||
filter: {
|
||||
liked: string;
|
||||
};
|
||||
page?: {
|
||||
offset?: number;
|
||||
limit: number;
|
||||
};
|
||||
}
|
||||
|
||||
export default class PostLikesModalState<P extends PostLikesModalListParams = PostLikesModalListParams> extends PaginatedListState<User, P> {
|
||||
constructor(params: P, page: number = 1) {
|
||||
const limit = 10;
|
||||
|
||||
params.page = { ...(params.page || {}), limit };
|
||||
|
||||
super(params, page, limit);
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
return 'users';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user