From 126b797212a57ec259faa7de3e92d55fe8ebfd37 Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Mon, 25 May 2026 14:51:01 +0300 Subject: [PATCH] =?UTF-8?q?fix(admin-ui):=20reviews=20=E2=80=94=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B7=D0=BE=D0=BB=D0=B2=D0=B8=D1=82=D1=8C=20dictionaryId?= =?UTF-8?q?=20=D0=B2=20=D0=B8=D0=BC=D1=8F=20=D1=81=D0=BB=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=80=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В таблицах /reviews (Запись + Мои → Запись) колонка «Объект» показывала UUID-prefix («254a662f…/REFLEXIO-OPTIC») вместо имени словаря, а ссылка вела на /dictionaries/ — 404 (route ожидает name, не UUID). DraftResponse несёт только dictionaryId (UUID); dictionaryName есть только у schema-drafts. Резолвим через useDictionaries() — кешируется TanStack Query, дополнительных запросов не делает. Fallback на UUID-prefix без link'а, когда dict не в выдаче (scope-hide / удалён) — лучше чем ведущая в 404 ссылка. Files: - routes/reviews.tsx — records-tab table (queue, ReviewsPage) - components/reviews/MyDraftsPanel.tsx — RecordRow ("Мои" tab) --- .../src/components/reviews/MyDraftsPanel.tsx | 36 +++++++++++++----- ordinis-admin-ui/src/routes/reviews.tsx | 38 +++++++++++++++---- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/ordinis-admin-ui/src/components/reviews/MyDraftsPanel.tsx b/ordinis-admin-ui/src/components/reviews/MyDraftsPanel.tsx index 6109647..11c43ea 100644 --- a/ordinis-admin-ui/src/components/reviews/MyDraftsPanel.tsx +++ b/ordinis-admin-ui/src/components/reviews/MyDraftsPanel.tsx @@ -16,7 +16,7 @@ import { TableHeaderCell, TableRow, } from '@/ui' -import { useMyDrafts, useMySchemaDrafts } from '@/api/queries' +import { useDictionaries, useMyDrafts, useMySchemaDrafts } from '@/api/queries' import { UserCell } from '@/lib/useUserDisplay' import type { DraftOperation, @@ -303,6 +303,14 @@ function RecordRow({ onClick: () => void }) { const { t } = useTranslation() + // DraftResponse несёт только dictionaryId (UUID) — резолвим в name через + // global dictionaries list (кешируется TanStack Query). Fallback на + // UUID-prefix без link'а если dict не в выдаче (scope-hide / deleted). + const dictionaries = useDictionaries() + const dictName = useMemo( + () => dictionaries.data?.find((d) => d.id === draft.dictionaryId)?.name, + [dictionaries.data, draft.dictionaryId], + ) return ( @@ -311,15 +319,23 @@ function RecordRow({ - - {draft.dictionaryId.slice(0, 8)}… - / - {draft.businessKey} - + {dictName ? ( + + {dictName} + / + {draft.businessKey} + + ) : ( + + {draft.dictionaryId.slice(0, 8)}… + / + {draft.businessKey} + + )} {draft.operation} diff --git a/ordinis-admin-ui/src/routes/reviews.tsx b/ordinis-admin-ui/src/routes/reviews.tsx index fafdf9b..1d0e84c 100644 --- a/ordinis-admin-ui/src/routes/reviews.tsx +++ b/ordinis-admin-ui/src/routes/reviews.tsx @@ -27,6 +27,7 @@ import axios from 'axios' import { useAuth } from 'react-oidc-context' import { ArrowCounterClockwiseIcon, CheckCircleIcon, XCircleIcon } from '@phosphor-icons/react' import { + useDictionaries, useDraft, useLiveRecord, useMyDrafts, @@ -162,6 +163,15 @@ function ReviewsPage() { const { t } = useTranslation() const queue = useReviewQueue(0, 50) const schemaQueue = useSchemaReviewQueue(0, 50) + // DraftResponse несёт только dictionaryId (UUID) — резолвим в name через + // global dictionaries list (кешируется TanStack Query, ~free). Fallback на + // UUID-prefix когда dict недоступен (scope-hide / deleted). + const dictionaries = useDictionaries() + const dictNameById = useMemo(() => { + const map = new Map() + for (const d of dictionaries.data ?? []) map.set(d.id, d.name) + return map + }, [dictionaries.data]) // Counts для "Мои" tab badge — sum of attention-needing drafts (pending + // WIP). Recompute дешёвый (linear over ≤100 items), refetch interval 30s // делает badge самозаживляющим без manual invalidation. @@ -463,13 +473,27 @@ function ReviewsPage() { /> - - {d.dictionaryId.slice(0, 8)}… - + {(() => { + const dictName = dictNameById.get(d.dictionaryId) + if (dictName) { + return ( + + {dictName} + + ) + } + // Dict скрыт scope-фильтром или удалён — UUID-prefix + // как fallback, без link'а (вёл бы в 404). + return ( + + {d.dictionaryId.slice(0, 8)}… + + ) + })()} {d.businessKey}