Trollboard expandable (#1354)

* wip

* hide necessary column in trollboard

* remove console.log

* fix build

* clean up

* remove commented code
This commit is contained in:
notmd
2023-02-09 09:20:27 +01:00
committed by GitHub
parent 7c4ff73241
commit ef548edb72
7 changed files with 153 additions and 60 deletions
@@ -2,19 +2,20 @@ import { Box, CircularProgress, Flex, Link, useColorModeValue } from "@chakra-ui
import { createColumnHelper } from "@tanstack/react-table";
import { MoreHorizontal } from "lucide-react";
import NextLink from "next/link";
import { useSession } from "next-auth/react";
import { useTranslation } from "next-i18next";
import React, { useMemo } from "react";
import { useHasRole } from "src/hooks/auth/useHasRole";
import { LeaderboardEntity, LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard";
import { DataTable, DataTableColumnDef } from "../DataTable";
import { DataTable, DataTableColumnDef } from "../DataTable/DataTable";
import { createJsonExpandRowModel } from "../DataTable/jsonExpandRowModel";
import { useBoardPagination } from "./useBoardPagination";
import { useBoardRowProps } from "./useBoardRowProps";
import { useFetchBoard } from "./useFetchBoard";
type WindowLeaderboardEntity = LeaderboardEntity & { isSpaceRow?: boolean };
const columnHelper = createColumnHelper<WindowLeaderboardEntity>();
const jsonExpandRowModel = createJsonExpandRowModel<WindowLeaderboardEntity>();
/**
* Presents a grid of leaderboard entries with more detailed information.
*/
@@ -39,17 +40,24 @@ export const LeaderboardTable = ({
} = useFetchBoard<LeaderboardReply & { user_stats_window?: LeaderboardReply["leaderboard"] }>(
`/api/leaderboard?time_frame=${timeFrame}&limit=${limit}&includeUserStats=${!hideCurrentUserRanking}`
);
const { data: session } = useSession();
const isAdmin = session?.user?.role === "admin";
const isAdmin = useHasRole("admin");
const columns: DataTableColumnDef<WindowLeaderboardEntity>[] = useMemo(
() => [
{
...columnHelper.accessor("rank", {
header: t("rank"),
cell: ({ row, getValue }) => (row.original.isSpaceRow ? <SpaceRow></SpaceRow> : getValue()),
cell: (ctx) =>
ctx.row.original.isSpaceRow ? (
<SpaceRow></SpaceRow>
) : isAdmin ? (
jsonExpandRowModel.renderCell(ctx)
) : (
ctx.getValue()
),
}),
span: (cell) => (cell.row.original.isSpaceRow ? 6 : undefined),
span: (cell) => (cell.row.original.isSpaceRow ? 6 : jsonExpandRowModel.span(cell)),
},
columnHelper.accessor("display_name", {
header: t("user"),
@@ -82,17 +90,17 @@ export const LeaderboardTable = ({
data: paginatedData,
end,
...pagnationProps
} = useBoardPagination({ rowPerPage, data: reply?.leaderboard, limit });
const data: WindowLeaderboardEntity[] = useMemo(() => {
if (hideCurrentUserRanking || !reply?.user_stats_window) {
} = useBoardPagination({ rowPerPage, data: jsonExpandRowModel.toExpandable(reply?.leaderboard || []), limit });
const data = useMemo(() => {
if (hideCurrentUserRanking || !reply?.user_stats_window || reply.user_stats_window.length === 0) {
return paginatedData;
}
const userStatsWindow: WindowLeaderboardEntity[] = reply.user_stats_window;
const userStatsWindow: WindowLeaderboardEntity[] = jsonExpandRowModel.toExpandable(reply.user_stats_window);
const userStats = userStatsWindow.find((stats) => stats.highlighted);
if (userStats && userStats.rank > end) {
paginatedData.push(
{ isSpaceRow: true } as WindowLeaderboardEntity,
...reply.user_stats_window.filter(
...userStatsWindow.filter(
(stats) => paginatedData.findIndex((leaderBoardEntity) => leaderBoardEntity.user_id === stats.user_id) === -1
) // filter to avoid duplicated row
);
@@ -116,6 +124,7 @@ export const LeaderboardTable = ({
columns={columns}
caption={lastUpdated}
rowProps={rowProps}
getSubRows={jsonExpandRowModel.getSubRows}
{...pagnationProps}
></DataTable>
);
@@ -1,26 +1,42 @@
import { Box, CircularProgress, Flex, Link } from "@chakra-ui/react";
import { Box, CircularProgress, Flex, IconButton, Link, Tooltip } from "@chakra-ui/react";
import { createColumnHelper } from "@tanstack/react-table";
import { ThumbsDown, ThumbsUp } from "lucide-react";
import { Mail, ThumbsDown, ThumbsUp, User } from "lucide-react";
import NextLink from "next/link";
import { FetchTrollBoardResponse, TrollboardEntity, TrollboardTimeFrame } from "src/types/Trollboard";
import { DataTable } from "../DataTable";
import { DataTable, DataTableColumnDef } from "../DataTable/DataTable";
import { createJsonExpandRowModel } from "../DataTable/jsonExpandRowModel";
import { Discord } from "../Icons/Discord";
import { useBoardPagination } from "./useBoardPagination";
import { useBoardRowProps } from "./useBoardRowProps";
import { useFetchBoard } from "./useFetchBoard";
const columnHelper = createColumnHelper<TrollboardEntity>();
const toPercentage = (num: number) => `${Math.round(num * 100)}%`;
const jsonExpandRowModel = createJsonExpandRowModel<TrollboardEntity>();
const columns = [
columnHelper.accessor("rank", {}),
const columns: DataTableColumnDef<TrollboardEntity>[] = [
{
...columnHelper.accessor("rank", {
cell: jsonExpandRowModel.renderCell,
}),
span: jsonExpandRowModel.span,
},
columnHelper.accessor("display_name", {
header: "Display name",
cell: ({ getValue, row }) => (
<Link as={NextLink} href={`/admin/manage_user/${row.original.user_id}`}>
{getValue()}
</Link>
),
cell: ({ getValue, row }) => {
const isEmail = row.original.auth_method === "local";
return (
<Flex gap="2" alignItems="center">
<Link as={NextLink} href={`/admin/manage_user/${row.original.user_id}`}>
{getValue()}
</Link>
<Tooltip label={`This user signin with ${isEmail ? "email" : "discord"}`}>
{isEmail ? <Mail size="20"></Mail> : <Discord size="20"></Discord>}
</Tooltip>
</Flex>
);
},
}),
columnHelper.accessor("troll_score", {
header: "Troll score",
@@ -45,36 +61,19 @@ const columns = [
columnHelper.accessor((row) => row.spam + row.spam_prompts, {
header: "Spam",
}),
columnHelper.accessor("lang_mismach", {
header: "Lang mismach",
}),
columnHelper.accessor("not_appropriate", {
header: "Not appropriate",
}),
columnHelper.accessor("pii", {}),
columnHelper.accessor("hate_speech", {
header: "Hate speech",
}),
columnHelper.accessor("sexual_content", {
header: "Sexual Content",
}),
columnHelper.accessor("political_content", {
header: "Political Content",
}),
columnHelper.accessor("quality", {
cell: ({ getValue }) => toPercentage(getValue()),
}),
columnHelper.accessor("helpfulness", {
cell: ({ getValue }) => toPercentage(getValue()),
}),
columnHelper.accessor("humor", {
cell: ({ getValue }) => toPercentage(getValue()),
}),
columnHelper.accessor("violence", {
cell: ({ getValue }) => toPercentage(getValue()),
}),
columnHelper.accessor("toxicity", {
cell: ({ getValue }) => toPercentage(getValue()),
cell: ({ getValue }) => toPercentage(getValue() || 0),
}),
columnHelper.accessor((row) => row.user_id, {
header: "Actions",
cell: ({ row }) => (
<IconButton
as={NextLink}
href={`/admin/manage_user/${row.original.user_id}`}
aria-label={"View user"}
icon={<User></User>}
></IconButton>
),
}),
];
@@ -94,7 +93,11 @@ export const TrollboardTable = ({
lastUpdated,
} = useFetchBoard<FetchTrollBoardResponse>(`/api/admin/trollboard?time_frame=${timeFrame}&limit=${limit}`);
const { data, ...paginationProps } = useBoardPagination({ rowPerPage, data: trollboardRes?.trollboard, limit });
const { data, ...paginationProps } = useBoardPagination<TrollboardEntity>({
rowPerPage,
data: jsonExpandRowModel.toExpandable(trollboardRes?.trollboard),
limit,
});
const rowProps = useBoardRowProps<TrollboardEntity>();
if (isLoading) {
return <CircularProgress isIndeterminate></CircularProgress>;
@@ -112,11 +115,12 @@ export const TrollboardTable = ({
},
}}
>
<DataTable<TrollboardEntity>
<DataTable
data={data}
columns={columns}
caption={lastUpdated}
rowProps={rowProps}
getSubRows={jsonExpandRowModel.getSubRows}
{...paginationProps}
></DataTable>
</Box>
@@ -2,7 +2,7 @@ import { useColorModeValue, useToken } from "@chakra-ui/react";
import { useCallback } from "react";
import { colors } from "src/styles/Theme/colors";
import { DataTableRowPropsCallback } from "../DataTable";
import { DataTableRowPropsCallback } from "../DataTable/DataTable";
export const useBoardRowProps = <T extends { highlighted: boolean }>() => {
const borderColor = useToken("colors", useColorModeValue(colors.light.active, colors.dark.active));