From 986cf02b0d6c9828ef1667966ff14a82b5a14999 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Mon, 27 Jul 2026 12:16:42 +0300 Subject: [PATCH] Update CollectionSuggestions and GroupSuggestions to default to collapsed state; enhance GenresPanel with pagination and sorting improvements Modified CollectionSuggestions and GroupSuggestions components to start in a collapsed state for better UI experience. Enhanced GenresPanel by implementing pagination and updating sorting functionality to ensure a more manageable display of genre data, improving overall usability. --- .../collections/CollectionSuggestions.tsx | 4 ++- .../src/features/admin/genres/GenresPanel.tsx | 32 ++++++++++++++++--- .../admin/groups/GroupSuggestions.tsx | 4 ++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/frontend/src/features/admin/collections/CollectionSuggestions.tsx b/frontend/src/features/admin/collections/CollectionSuggestions.tsx index a5d60f8..bb8c24b 100644 --- a/frontend/src/features/admin/collections/CollectionSuggestions.tsx +++ b/frontend/src/features/admin/collections/CollectionSuggestions.tsx @@ -21,7 +21,9 @@ export function CollectionSuggestions() { const { t } = useTranslation() const queryClient = useQueryClient() const onError = useApiError() - const [collapsed, setCollapsed] = useState(false) + // Свёрнуто по умолчанию: предложения — подсказка, а не главное на экране, и развёрнутый + // список из десятка строк отодвигал бы сам справочник за нижний край. + const [collapsed, setCollapsed] = useState(true) const [showExisting, setShowExisting] = useState(false) const { data, isLoading } = useQuery({ diff --git a/frontend/src/features/admin/genres/GenresPanel.tsx b/frontend/src/features/admin/genres/GenresPanel.tsx index d107ed7..daf3bde 100644 --- a/frontend/src/features/admin/genres/GenresPanel.tsx +++ b/frontend/src/features/admin/genres/GenresPanel.tsx @@ -14,6 +14,7 @@ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from ' import { Input } from '@/shared/ui/input' import { Label } from '@/shared/ui/label' import { sortRows, useTableSort } from '@/shared/lib/table-sort' +import { Pager } from '@/shared/ui/pager' import { SortHeader } from '@/shared/ui/sortable' import { createGenre, deleteGenre, listGenres, updateGenre } from './api' @@ -36,6 +37,13 @@ const editSchema = z.object({ type CreateValues = z.infer type EditValues = z.infer +/** + * Жанров бывает под сотню (базовый набор плюс заведённые руками), и все они грузятся одним + * запросом — список нужен целиком селектам жанра по всей админке. Поэтому страницы режутся здесь, + * а не на сервере: таблица остаётся читаемой, а пикеры продолжают получать полный справочник. + */ +const PAGE_SIZE = 20 + /** Псевдонимы вводятся одной строкой через запятую — их редко больше десятка. */ function parseAliases(value: string | undefined): string[] { return (value ?? '') @@ -52,6 +60,8 @@ export function GenresPanel() { queryFn: listGenres, }) const { sort, toggle } = useTableSort('sortOrder', false) + const [page, setPage] = useState(1) + const sortedGenres = sortRows(genres ?? [], sort, { sortOrder: (g) => g.sortOrder, name: (g) => g.name.toLowerCase(), @@ -59,6 +69,16 @@ export function GenresPanel() { showCount: (g) => g.showCount, }) + // Страница может уехать за конец списка после удаления — тогда показываем последнюю. + const totalPages = Math.max(1, Math.ceil(sortedGenres.length / PAGE_SIZE)) + const current = Math.min(page, totalPages) + const visible = sortedGenres.slice((current - 1) * PAGE_SIZE, current * PAGE_SIZE) + + const sortColumn = (key: string) => { + setPage(1) + toggle(key) + } + const invalidate = () => queryClient.invalidateQueries({ queryKey: qk.genres.all }) const reportError = useApiError() @@ -145,26 +165,26 @@ export function GenresPanel() { label={t('admin.genres.order')} sortKey="sortOrder" sort={sort} - onToggle={toggle} + onToggle={sortColumn} /> {t('admin.genres.aliases')} {t('common.actions')} @@ -177,7 +197,7 @@ export function GenresPanel() { )} - {sortedGenres.map((genre) => ( + {visible.map((genre) => ( {genre.sortOrder} @@ -212,6 +232,8 @@ export function GenresPanel() { + + diff --git a/frontend/src/features/admin/groups/GroupSuggestions.tsx b/frontend/src/features/admin/groups/GroupSuggestions.tsx index e28d119..605894c 100644 --- a/frontend/src/features/admin/groups/GroupSuggestions.tsx +++ b/frontend/src/features/admin/groups/GroupSuggestions.tsx @@ -23,7 +23,9 @@ export function GroupSuggestions() { const { t } = useTranslation() const queryClient = useQueryClient() const onError = useApiError() - const [collapsed, setCollapsed] = useState(false) + // Свёрнуто по умолчанию: предложения — подсказка, а не главное на экране, и развёрнутый + // список из десятка строк отодвигал бы сам справочник за нижний край. + const [collapsed, setCollapsed] = useState(true) const [showExisting, setShowExisting] = useState(false) const { data, isLoading } = useQuery({