mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-09-12 12:03:06 +08:00
Show current user rank in leaderboard (#1263)
close #1000 maybe #1178 too * Show current user rank in the leaderboard with +-1 user (only on leaderboard * Extend auto_main script to use random user. * Support colSpan in the DataTable component (I haven't verified colSpan in header yet, leave that until we need it) * Refactor OasstError to include the path and request method.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { CircularProgress, useColorModeValue, useToken } from "@chakra-ui/react";
|
||||
import { Box, CircularProgress, Flex, useColorModeValue, useToken } from "@chakra-ui/react";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { MoreHorizontal } from "lucide-react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { get } from "src/lib/api";
|
||||
@@ -7,9 +8,11 @@ import { colors } from "src/styles/Theme/colors";
|
||||
import { LeaderboardEntity, LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard";
|
||||
import useSWRImmutable from "swr/immutable";
|
||||
|
||||
import { DataTable, DataTableRowPropsCallback } from "../DataTable";
|
||||
import { DataTable, DataTableColumnDef, DataTableRowPropsCallback } from "../DataTable";
|
||||
|
||||
const columnHelper = createColumnHelper<LeaderboardEntity>();
|
||||
type WindowLeaderboardEntity = LeaderboardEntity & { isSpaceRow?: boolean };
|
||||
|
||||
const columnHelper = createColumnHelper<WindowLeaderboardEntity>();
|
||||
|
||||
/**
|
||||
* Presents a grid of leaderboard entries with more detailed information.
|
||||
@@ -18,10 +21,12 @@ export const LeaderboardTable = ({
|
||||
timeFrame,
|
||||
limit: limit,
|
||||
rowPerPage,
|
||||
hideCurrentUserRanking,
|
||||
}: {
|
||||
timeFrame: LeaderboardTimeFrame;
|
||||
limit: number;
|
||||
rowPerPage: number;
|
||||
hideCurrentUserRanking?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation("leaderboard");
|
||||
|
||||
@@ -29,15 +34,19 @@ export const LeaderboardTable = ({
|
||||
data: reply,
|
||||
isLoading,
|
||||
error,
|
||||
} = useSWRImmutable<LeaderboardReply>(`/api/leaderboard?time_frame=${timeFrame}&limit=${limit}`, get, {
|
||||
revalidateOnMount: true,
|
||||
});
|
||||
|
||||
const columns = useMemo(
|
||||
} = useSWRImmutable<LeaderboardReply & { user_stats_window: LeaderboardReply["leaderboard"] }>(
|
||||
`/api/leaderboard?time_frame=${timeFrame}&limit=${limit}&includeUserStats=${!hideCurrentUserRanking}`,
|
||||
get
|
||||
);
|
||||
const columns: DataTableColumnDef<WindowLeaderboardEntity>[] = useMemo(
|
||||
() => [
|
||||
columnHelper.accessor("rank", {
|
||||
header: t("rank"),
|
||||
}),
|
||||
{
|
||||
...columnHelper.accessor("rank", {
|
||||
header: t("rank"),
|
||||
cell: ({ row, getValue }) => (row.original.isSpaceRow ? <SpaceRow></SpaceRow> : getValue()),
|
||||
}),
|
||||
span: (cell) => (cell.row.original.isSpaceRow ? 6 : undefined),
|
||||
},
|
||||
columnHelper.accessor("display_name", {
|
||||
header: t("user"),
|
||||
}),
|
||||
@@ -63,15 +72,72 @@ export const LeaderboardTable = ({
|
||||
}, [t, reply?.last_updated]);
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const data = useMemo(() => {
|
||||
const data: WindowLeaderboardEntity[] = useMemo(() => {
|
||||
if (!reply) {
|
||||
return [];
|
||||
}
|
||||
const start = (page - 1) * rowPerPage;
|
||||
return reply?.leaderboard.slice(start, start + rowPerPage) || [];
|
||||
}, [rowPerPage, page, reply?.leaderboard]);
|
||||
const end = start + rowPerPage;
|
||||
const leaderBoardEntities = reply.leaderboard.slice(start, end);
|
||||
if (hideCurrentUserRanking) {
|
||||
return leaderBoardEntities;
|
||||
}
|
||||
const userStatsWindow: WindowLeaderboardEntity[] = reply.user_stats_window;
|
||||
const userStats = userStatsWindow.find((stats) => stats.highlighted);
|
||||
if (userStats.rank > end) {
|
||||
leaderBoardEntities.push(
|
||||
{ isSpaceRow: true } as WindowLeaderboardEntity,
|
||||
...reply.user_stats_window.filter(
|
||||
(stats) =>
|
||||
leaderBoardEntities.findIndex((leaderBoardEntity) => leaderBoardEntity.user_id === stats.user_id) === -1
|
||||
) // filter to avoid duplicated row
|
||||
);
|
||||
}
|
||||
return leaderBoardEntities;
|
||||
}, [page, rowPerPage, reply, hideCurrentUserRanking]);
|
||||
|
||||
const rowProps = useLeaderboardRowProps();
|
||||
|
||||
if (isLoading) {
|
||||
return <CircularProgress isIndeterminate></CircularProgress>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <span>Unable to load leaderboard</span>;
|
||||
}
|
||||
|
||||
const maxPage = Math.ceil(reply.leaderboard.length / rowPerPage);
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
caption={lastUpdated}
|
||||
disablePagination={limit <= rowPerPage}
|
||||
disableNext={page >= maxPage}
|
||||
disablePrevious={page === 1}
|
||||
onNextClick={() => setPage((p) => p + 1)}
|
||||
onPreviousClick={() => setPage((p) => p - 1)}
|
||||
rowProps={rowProps}
|
||||
></DataTable>
|
||||
);
|
||||
};
|
||||
|
||||
const SpaceRow = () => {
|
||||
const color = useColorModeValue("gray.600", "gray.400");
|
||||
return (
|
||||
<Flex justify="center">
|
||||
<Box as={MoreHorizontal} color={color}></Box>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const useLeaderboardRowProps = () => {
|
||||
const borderColor = useToken("colors", useColorModeValue(colors.light.active, colors.dark.active));
|
||||
const rowProps = useCallback<DataTableRowPropsCallback<LeaderboardEntity>>(
|
||||
return useCallback<DataTableRowPropsCallback<WindowLeaderboardEntity>>(
|
||||
(row) => {
|
||||
return row.original.highlighted
|
||||
const rowData = row.original;
|
||||
return rowData.highlighted
|
||||
? {
|
||||
sx: {
|
||||
// https://stackoverflow.com/questions/37963524/how-to-apply-border-radius-to-tr-in-bootstrap
|
||||
@@ -93,28 +159,4 @@ export const LeaderboardTable = ({
|
||||
},
|
||||
[borderColor]
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
return <CircularProgress isIndeterminate></CircularProgress>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <span>Unable to load leaderboard</span>;
|
||||
}
|
||||
|
||||
const maxPage = Math.ceil(reply.leaderboard.length / rowPerPage);
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
caption={lastUpdated}
|
||||
disablePagination={limit <= rowPerPage}
|
||||
disableNext={page === maxPage}
|
||||
disablePrevious={page === 1}
|
||||
onNextClick={() => setPage((p) => p + 1)}
|
||||
onPreviousClick={() => setPage((p) => p - 1)}
|
||||
rowProps={rowProps}
|
||||
></DataTable>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user