mirror of
https://github.com/flarum/core.git
synced 2025-08-05 07:57:46 +02:00
perf(flags): add pagination to flags list (#3931)
This commit is contained in:
@@ -8,6 +8,8 @@ import HeaderListItem from 'flarum/forum/components/HeaderListItem';
|
|||||||
import type Mithril from 'mithril';
|
import type Mithril from 'mithril';
|
||||||
import type Post from 'flarum/common/models/Post';
|
import type Post from 'flarum/common/models/Post';
|
||||||
import type FlagListState from '../states/FlagListState';
|
import type FlagListState from '../states/FlagListState';
|
||||||
|
import type Flag from '../models/Flag';
|
||||||
|
import { Page } from 'flarum/common/states/PaginatedListState';
|
||||||
|
|
||||||
export interface IFlagListAttrs extends ComponentAttrs {
|
export interface IFlagListAttrs extends ComponentAttrs {
|
||||||
state: FlagListState;
|
state: FlagListState;
|
||||||
@@ -16,23 +18,29 @@ export interface IFlagListAttrs extends ComponentAttrs {
|
|||||||
export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttrs> extends Component<CustomAttrs, FlagListState> {
|
export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttrs> extends Component<CustomAttrs, FlagListState> {
|
||||||
oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
|
||||||
super.oninit(vnode);
|
super.oninit(vnode);
|
||||||
this.state = this.attrs.state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
const flags = this.state.cache || [];
|
const state = this.attrs.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderList
|
<HeaderList
|
||||||
className="FlagList"
|
className="FlagList"
|
||||||
title={app.translator.trans('flarum-flags.forum.flagged_posts.title')}
|
title={app.translator.trans('flarum-flags.forum.flagged_posts.title')}
|
||||||
hasItems={flags.length}
|
hasItems={state.hasItems()}
|
||||||
loading={this.state.loading}
|
loading={state.isLoading()}
|
||||||
emptyText={app.translator.trans('flarum-flags.forum.flagged_posts.empty_text')}
|
emptyText={app.translator.trans('flarum-flags.forum.flagged_posts.empty_text')}
|
||||||
|
loadMore={() => state.hasNext() && !state.isLoadingNext() && state.loadNext()}
|
||||||
>
|
>
|
||||||
<ul className="HeaderListGroup-content">
|
<ul className="HeaderListGroup-content">{this.content(state)}</ul>
|
||||||
{!this.state.loading &&
|
</HeaderList>
|
||||||
flags.map((flag) => {
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
content(state: FlagListState) {
|
||||||
|
if (!state.isLoading() && state.hasItems()) {
|
||||||
|
return state.getPages().map((page: Page<Flag>) => {
|
||||||
|
return page.items.map((flag: Flag) => {
|
||||||
const post = flag.post() as Post;
|
const post = flag.post() as Post;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -50,15 +58,15 @@ export default class FlagList<CustomAttrs extends IFlagListAttrs = IFlagListAttr
|
|||||||
datetime={flag.createdAt()}
|
datetime={flag.createdAt()}
|
||||||
href={app.route.post(post)}
|
href={app.route.post(post)}
|
||||||
onclick={(e: MouseEvent) => {
|
onclick={(e: MouseEvent) => {
|
||||||
app.flags.index = post;
|
|
||||||
e.redraw = false;
|
e.redraw = false;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
});
|
||||||
</ul>
|
});
|
||||||
</HeaderList>
|
}
|
||||||
);
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ export default class FlagsDropdown<CustomAttrs extends IFlagsDropdownAttrs = IFl
|
|||||||
}
|
}
|
||||||
|
|
||||||
getUnreadCount() {
|
getUnreadCount() {
|
||||||
return app.flags.cache ? app.flags.cache.length : app.forum.attribute<number>('flagCount');
|
return app.forum.attribute<number>('flagCount');
|
||||||
}
|
}
|
||||||
|
|
||||||
getNewCount() {
|
getNewCount() {
|
||||||
|
@@ -1,39 +1,33 @@
|
|||||||
import type ForumApplication from 'flarum/forum/ForumApplication';
|
import type ForumApplication from 'flarum/forum/ForumApplication';
|
||||||
import type Flag from '../models/Flag';
|
import type Flag from '../models/Flag';
|
||||||
import type Post from 'flarum/common/models/Post';
|
import PaginatedListState from 'flarum/common/states/PaginatedListState';
|
||||||
|
|
||||||
export default class FlagListState {
|
export default class FlagListState extends PaginatedListState<Flag> {
|
||||||
public app: ForumApplication;
|
public app: ForumApplication;
|
||||||
public loading = false;
|
|
||||||
public cache: Flag[] | null = null;
|
|
||||||
public index: Post | false | null = null;
|
|
||||||
|
|
||||||
constructor(app: ForumApplication) {
|
constructor(app: ForumApplication) {
|
||||||
|
super({}, 1, null);
|
||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get type(): string {
|
||||||
|
return 'flags';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load flags into the application's cache if they haven't already
|
* Load flags into the application's cache if they haven't already
|
||||||
* been loaded.
|
* been loaded.
|
||||||
*/
|
*/
|
||||||
load() {
|
load(): Promise<void> {
|
||||||
if (this.cache && !this.app.session.user!.attribute<number>('newFlagCount')) {
|
if (this.app.session.user?.attribute<number>('newFlagCount')) {
|
||||||
return;
|
this.pages = [];
|
||||||
|
this.location = { page: 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = true;
|
if (this.pages.length > 0) {
|
||||||
m.redraw();
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
this.app.store
|
return super.loadNext();
|
||||||
.find<Flag[]>('flags')
|
|
||||||
.then((flags) => {
|
|
||||||
this.app.session.user!.pushAttributes({ newFlagCount: 0 });
|
|
||||||
this.cache = flags.sort((a, b) => b.createdAt()!.getTime() - a.createdAt()!.getTime());
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
.then(() => {
|
|
||||||
this.loading = false;
|
|
||||||
m.redraw();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ use Flarum\Api\Controller\AbstractListController;
|
|||||||
use Flarum\Flags\Api\Serializer\FlagSerializer;
|
use Flarum\Flags\Api\Serializer\FlagSerializer;
|
||||||
use Flarum\Flags\Flag;
|
use Flarum\Flags\Flag;
|
||||||
use Flarum\Http\RequestUtil;
|
use Flarum\Http\RequestUtil;
|
||||||
|
use Flarum\Http\UrlGenerator;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Tobscure\JsonApi\Document;
|
use Tobscure\JsonApi\Document;
|
||||||
|
|
||||||
@@ -28,26 +29,52 @@ class ListFlagsController extends AbstractListController
|
|||||||
'post.discussion'
|
'post.discussion'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected UrlGenerator $url
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
protected function data(ServerRequestInterface $request, Document $document): iterable
|
protected function data(ServerRequestInterface $request, Document $document): iterable
|
||||||
{
|
{
|
||||||
$actor = RequestUtil::getActor($request);
|
$actor = RequestUtil::getActor($request);
|
||||||
$include = $this->extractInclude($request);
|
|
||||||
|
|
||||||
$actor->assertRegistered();
|
$actor->assertRegistered();
|
||||||
|
|
||||||
$actor->read_flags_at = Carbon::now();
|
$actor->read_flags_at = Carbon::now();
|
||||||
$actor->save();
|
$actor->save();
|
||||||
|
|
||||||
$flags = Flag::whereVisibleTo($actor)
|
$limit = $this->extractLimit($request);
|
||||||
->latest('flags.created_at')
|
$offset = $this->extractOffset($request);
|
||||||
->groupBy('post_id')
|
$include = $this->extractInclude($request);
|
||||||
->get();
|
|
||||||
|
|
||||||
if (in_array('post.user', $include)) {
|
if (in_array('post.user', $include)) {
|
||||||
$include[] = 'post.user.groups';
|
$include[] = 'post.user.groups';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->loadRelations($flags, $include);
|
$flags = Flag::whereVisibleTo($actor)
|
||||||
|
->latest('flags.created_at')
|
||||||
|
->groupBy('post_id')
|
||||||
|
->limit($limit + 1)
|
||||||
|
->offset($offset)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$this->loadRelations($flags, $include, $request);
|
||||||
|
|
||||||
|
$flags = $flags->all();
|
||||||
|
|
||||||
|
$areMoreResults = false;
|
||||||
|
|
||||||
|
if (count($flags) > $limit) {
|
||||||
|
array_pop($flags);
|
||||||
|
$areMoreResults = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addPaginationData(
|
||||||
|
$document,
|
||||||
|
$request,
|
||||||
|
$this->url->to('api')->route('flags.index'),
|
||||||
|
$areMoreResults ? null : 0
|
||||||
|
);
|
||||||
|
|
||||||
return $flags;
|
return $flags;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user