Skip to content

Commit

Permalink
Fix pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
l7ssha committed Dec 18, 2024
1 parent 84b4cf7 commit 38df8d7
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 50 deletions.
35 changes: 19 additions & 16 deletions frontend/src/page/admin/GuildDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {fetchGuildDetails, fetchGuildTags, GuildDetails as GuildDetailsDto} from "../../service/api";
import {
fetchGuildDetails,
fetchGuildTags,
GuildDetails as GuildDetailsDto,
PaginationResponse,
Tag
} from "../../service/api";
import {Base} from "../../component/Base";
import {
Accordion,
Expand All @@ -11,17 +17,20 @@ import {
Typography
} from "@mui/material";
import {useParams} from "react-router-dom";
import React, {Suspense, use, useState} from "react";
import React, {Suspense, use, useEffect, useState} from "react";
import {getGuildNameElement} from "../../guildUtil";
import {DataGrid, GridColDef} from "@mui/x-data-grid";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import {useDebounce} from "use-debounce";
import useUpdateEffect from "../../util";

interface GuildDetailsDataProps {
dataPromise: Promise<GuildDetailsDto>
}

interface TagsDataPaperProps {
id: string,
}

const dateFormat = new Intl.DateTimeFormat('en-GB', { dateStyle: 'short', timeStyle: 'short' });

function FeaturesPaper({dataPromise}: GuildDetailsDataProps) {
Expand Down Expand Up @@ -49,19 +58,17 @@ function FeaturesPaper({dataPromise}: GuildDetailsDataProps) {
</Stack>;
}

function TagsDataPaper({dataPromise}: GuildDetailsDataProps) {
const data = use(dataPromise);

const [tags, setTags] = useState(data.tags);
function TagsDataPaper({id}: TagsDataPaperProps) {
const [tags, setTags] = useState<PaginationResponse<Tag>|null>(null);
const [searchQuery, setSearchQuery] = useState<string|null>(null);
const [searchQueryDebounced] = useDebounce(searchQuery, 500);
const [paginationModel, setPaginationModel] = useState({
pageSize: 5,
page: 0,
});

useUpdateEffect(() => {
fetchGuildTags({id: data.id, query: searchQueryDebounced ?? '', page: paginationModel.page, perPage: paginationModel.pageSize}).then((t) => setTags(t));
useEffect(() => {
fetchGuildTags({id: id, query: searchQueryDebounced ?? '', page: paginationModel.page, perPage: paginationModel.pageSize}).then((t) => setTags(t));
}, [searchQueryDebounced, paginationModel]);

const columns: GridColDef[] = [
Expand All @@ -76,7 +83,7 @@ function TagsDataPaper({dataPromise}: GuildDetailsDataProps) {
<Typography variant='h5'>Tags</Typography>
<TextField id="tag-name-filter" label="Name..." variant="outlined" size='small' onChange={(e) => setSearchQuery(e.target.value)} />
</Stack>
<DataGrid rows={tags} columns={columns} paginationModel={paginationModel} onPaginationModelChange={setPaginationModel} paginationMode="server" rowCount={-1} />
<DataGrid rows={tags?.data ?? []} columns={columns} paginationModel={paginationModel} onPaginationModelChange={setPaginationModel} paginationMode="server" rowCount={tags?.total ?? -1} />
</Stack>;
}

Expand All @@ -96,16 +103,12 @@ function GuildDetailsData({dataPromise}: GuildDetailsDataProps) {
<Typography fontWeight="bold">Features enabled: </Typography>
<Typography>{data.features.enabledFeatures.length}</Typography>
</Container>
<Container>
<Typography fontWeight="bold">Tags: </Typography>
<Typography>{data.tags.length}</Typography>
</Container>
</Stack>
}

export default function GuildDetails() {
const {id} = useParams()
const promise = fetchGuildDetails(id as string);
const promise = fetchGuildDetails(id!);

return <Base>
<Paper elevation={1} sx={{p: '5px', mb: '5px'}}>
Expand All @@ -115,7 +118,7 @@ export default function GuildDetails() {
</Paper>
<Paper elevation={1} sx={{p: '5px', mb: '5px'}}>
<Suspense fallback={<span>Loading...</span>}>
<TagsDataPaper dataPromise={promise} />
<TagsDataPaper id={id!} />
</Suspense>
</Paper>
<Paper elevation={1} sx={{p: '5px'}}>
Expand Down
21 changes: 9 additions & 12 deletions frontend/src/page/admin/Guilds.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {Suspense, use, useEffect, useState} from 'react';
import React, {Suspense, useEffect, useState} from 'react';
import {Base} from "../../component/Base";
import {fetchGuilds, fetchGuildTags, GuildSummary} from "../../service/api";
import {fetchGuilds, GuildSummary} from "../../service/api";
import {DataGrid, GridActionsCellItem, GridColDef, GridRowParams} from "@mui/x-data-grid";
import {Alert, Stack, Tooltip, Typography} from "@mui/material";
import {GridCell} from "../../component/GridCell";
Expand All @@ -9,7 +9,6 @@ import {getUser} from "../../service/auth";
import OpenInFullIcon from '@mui/icons-material/OpenInFull';
import {useNavigate} from "react-router-dom";
import {getGuildNameElement} from "../../guildUtil";
import useUpdateEffect from "../../util";

interface GuildRowDef {
id: string,
Expand Down Expand Up @@ -41,23 +40,21 @@ function mapApiDataToRows(guilds: GuildSummary[]): GuildRowDef[] {
});
}

const guildDataPromise = fetchGuilds().then(guilds => {
return mapApiDataToRows(guilds);
});

function Grid() {
const navigate = useNavigate();
const initialRows = use(guildDataPromise);

const [paginationModel, setPaginationModel] = useState({
pageSize: 25,
page: 0,
});
const [rows, setRows] = useState(initialRows);
const [rows, setRows] = useState<GuildRowDef[]>([]);
const [totalRows, setTotalRows] = useState(-1);

useUpdateEffect(() => {
useEffect(() => {
fetchGuilds({page: paginationModel.page, perPage: paginationModel.pageSize}).then(guilds => {
return mapApiDataToRows(guilds);
setTotalRows(guilds.total);

return mapApiDataToRows(guilds.data);
}).then((r) => setRows(r));
}, [paginationModel]);

Expand Down Expand Up @@ -94,7 +91,7 @@ function Grid() {
];

return (
<DataGrid rows={rows} columns={columns} paginationModel={paginationModel} onPaginationModelChange={setPaginationModel} paginationMode="server" rowCount={-1} />
<DataGrid rows={rows} columns={columns} paginationModel={paginationModel} onPaginationModelChange={setPaginationModel} paginationMode="server" rowCount={totalRows} />
);
}

Expand Down
16 changes: 11 additions & 5 deletions frontend/src/service/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ export interface GuildDetails {
roles: Role[],
channels: Channel[],
features: FeaturesDetails,
tags: Tag[],
}

export interface PaginationResponse<T> {
page: number,
perPage: number,
total: number,
data: T[],
}

interface PaginationParameters {
Expand All @@ -138,21 +144,21 @@ export async function fetchBotInfo(): Promise<BotInfo> {
return await request<BotInfo>({path: "/api/server-info"});
}

export async function fetchGuilds({perPage = 25, page = 0}: PaginationParameters = {}): Promise<GuildSummary[]> {
export async function fetchGuilds({perPage = 25, page = 0}: PaginationParameters = {}): Promise<PaginationResponse<GuildSummary>> {
const params = [["perPage", perPage.toString()], ["page", (page + 1).toString()]];

return await request<GuildSummary[]>({path: "/api/guilds", auth: true, searchParams: params});
return await request<PaginationResponse<GuildSummary>>({path: "/api/guilds", auth: true, searchParams: params});
}

export async function fetchGuildDetails(id: string): Promise<GuildDetails> {
return await request<GuildDetails>({path: `/api/guilds/${id}`, auth: true});
}

export async function fetchGuildTags({id, perPage = 5, page = 0, query}: FetchGuildTagsParameters): Promise<Tag[]> {
export async function fetchGuildTags({id, perPage = 5, page = 0, query}: FetchGuildTagsParameters): Promise<PaginationResponse<Tag>> {
const params = [["perPage", perPage.toString()], ["page", (page + 1).toString()]];
if (query != null && query !== '') {
params.push(["query", query])
}

return await request<Tag[]>({path: `/api/guilds/${id}/tags`, auth: true, searchParams: params});
return await request<PaginationResponse<Tag>>({path: `/api/guilds/${id}/tags`, auth: true, searchParams: params});
}
12 changes: 8 additions & 4 deletions lib/src/web_app/api_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:nyxx/nyxx.dart';
import 'package:running_on_dart/running_on_dart.dart';
import 'package:running_on_dart/src/web_app/jwt.dart';
import 'package:running_on_dart/src/web_app/mapper/guild_mapper.dart';
import 'package:running_on_dart/src/web_app/mapper/pagination_mapper.dart';
import 'package:running_on_dart/src/web_app/mapper/tags_mapper.dart';
import 'package:running_on_dart/src/web_app/utils.dart';
import 'package:running_on_dart/src/services/bot_info.dart';
Expand Down Expand Up @@ -35,9 +36,12 @@ class WebServer {

final guilds = client.guilds.cache.values.skip(perPage * (page - 1)).take(perPage);

final guildData = await mapGuildsToGuildReducedData(guilds).toList();

return createOkResponse(guildData);
return createOkResponse(createPaginationResponse(
data: await mapGuildsToGuildReducedData(guilds).toList(),
page: page,
perPage: perPage,
total: client.guilds.cache.length,
));
}

Future<shelf.Response> _handleGuildTags(shelf.Request request) async {
Expand All @@ -51,7 +55,7 @@ class WebServer {
final page = int.tryParse(request.requestedUri.queryParameters['page'] ?? '1') ?? 1;

return createOkResponse(
await mapGuildTagsToData(Snowflake.parse(guildParam), perPage, searchQuery: searchQuery, page: page).toList(),
await mapGuildTagsToData(Snowflake.parse(guildParam), perPage, searchQuery: searchQuery, page: page),
);
}

Expand Down
2 changes: 0 additions & 2 deletions lib/src/web_app/mapper/guild_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:nyxx/nyxx.dart';
import 'package:running_on_dart/src/modules/tag.dart';
import 'package:running_on_dart/src/repository/feature_settings.dart';
import 'package:running_on_dart/src/web_app/mapper/features_mapper.dart';
import 'package:running_on_dart/src/web_app/mapper/tags_mapper.dart';
import 'package:running_on_dart/src/web_app/utils.dart';

JsonApiResponse _mapChannelToData(Channel channel) {
Expand Down Expand Up @@ -129,6 +128,5 @@ Future<JsonApiResponse> mapGuildToDetailsData(Guild guild, int channelsLimit, in
'roles': roles,
'channels': channels,
'features': await mapGuildFeaturesToData(guild.id),
'tags': await mapGuildTagsToData(guild.id, tagsLimit).toList(),
};
}
11 changes: 11 additions & 0 deletions lib/src/web_app/mapper/pagination_mapper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:running_on_dart/src/web_app/utils.dart';

JsonApiResponse createPaginationResponse(
{required List<JsonApiResponse> data, required int total, required int perPage, required int page}) {
return {
'perPage': perPage,
'page': page,
'total': total,
'data': data,
};
}
31 changes: 20 additions & 11 deletions lib/src/web_app/mapper/tags_mapper.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import 'package:injector/injector.dart';
import 'package:nyxx/nyxx.dart';
import 'package:running_on_dart/src/models/tag.dart';
import 'package:running_on_dart/src/modules/tag.dart';
import 'package:running_on_dart/src/web_app/mapper/pagination_mapper.dart';
import 'package:running_on_dart/src/web_app/utils.dart';

Stream<JsonApiResponse> mapGuildTagsToData(Snowflake guildId, int tagsLimit,
{String? searchQuery, int page = 1}) async* {
JsonApiResponse _mapGuildTag(Tag tag) {
return {
'id': tag.id,
'name': tag.name,
'content': tag.content,
'enabled': tag.enabled,
'authorId': tag.authorId.toString(),
};
}

Future<JsonApiResponse> mapGuildTagsToData(Snowflake guildId, int tagsLimit,
{String? searchQuery, int page = 1}) async {
final tagsModule = Injector.appInstance.get<TagModule>();

var tags = tagsModule.getGuildTags(guildId);
if (searchQuery != null) {
tags = tags.where((tag) => tag.name.contains(searchQuery));
}

for (final tag in tags.skip(tagsLimit * (page - 1)).take(tagsLimit)) {
yield {
'id': tag.id,
'name': tag.name,
'content': tag.content,
'enabled': tag.enabled,
'authorId': tag.authorId.toString(),
};
}
return createPaginationResponse(
data: tags.skip(tagsLimit * (page - 1)).take(tagsLimit).map(_mapGuildTag).toList(),
total: tags.length,
perPage: tagsLimit,
page: page,
);
}

0 comments on commit 38df8d7

Please sign in to comment.