From 353130c5296275ab171268898b302ddbb523a0bb Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Wed, 6 May 2026 12:43:01 +0300 Subject: [PATCH] feat(admin-ui): group dictionaries by scope with color accent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 40 справочников в плоском grid тяжело сканировать. Разделили на секции PUBLIC / INTERNAL / RESTRICTED с цветными accent-полосами слева у карточек (emerald / amber / rose). Search фильтрует across all sections, пустые секции скрыты. Цвет даёт instant scan, секции — explicit разделение. --- ordinis-admin-ui/src/i18n.ts | 6 + .../src/routes/dictionaries.index.tsx | 112 +++++++++++++----- 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/ordinis-admin-ui/src/i18n.ts b/ordinis-admin-ui/src/i18n.ts index 40c1e44..b682037 100644 --- a/ordinis-admin-ui/src/i18n.ts +++ b/ordinis-admin-ui/src/i18n.ts @@ -68,6 +68,9 @@ i18n 'dict.list.recordCount_few': '{{count}} записи', 'dict.list.recordCount_many': '{{count}} записей', 'dict.list.recordCount_other': '{{count}} записей', + 'dict.list.section.PUBLIC': 'Публичные', + 'dict.list.section.INTERNAL': 'Внутренние', + 'dict.list.section.RESTRICTED': 'Ограниченные', 'dict.empty': 'В этом справочнике пока нет записей', 'dict.col.businessKey': 'Бизнес-ключ', 'dict.col.scope': 'Scope', @@ -239,6 +242,9 @@ i18n 'dict.list.found': 'Showing {{shown}} of {{total}}', 'dict.list.recordCount_one': '{{count}} record', 'dict.list.recordCount_other': '{{count}} records', + 'dict.list.section.PUBLIC': 'Public', + 'dict.list.section.INTERNAL': 'Internal', + 'dict.list.section.RESTRICTED': 'Restricted', 'dict.empty': 'No records in this dictionary yet', 'dict.col.businessKey': 'Business key', 'dict.col.scope': 'Scope', diff --git a/ordinis-admin-ui/src/routes/dictionaries.index.tsx b/ordinis-admin-ui/src/routes/dictionaries.index.tsx index 65e76bd..33bafa8 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.index.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.index.tsx @@ -12,7 +12,7 @@ import { } from '@nstart/ui' import { PlusIcon } from '@phosphor-icons/react' import { useDictionaries } from '@/api/queries' -import type { DictionaryDefinition } from '@/api/client' +import type { DataScope, DictionaryDefinition } from '@/api/client' import { DictionaryEditorDialog } from '@/components/schema/DictionaryEditorDialog' export const Route = createFileRoute('/dictionaries/')({ @@ -27,6 +27,20 @@ const matchesQuery = (d: DictionaryDefinition, q: string): boolean => { return haystack.includes(q) } +const SCOPE_ORDER: ReadonlyArray = ['PUBLIC', 'INTERNAL', 'RESTRICTED'] + +const SCOPE_DOT: Record = { + PUBLIC: 'bg-emerald-500', + INTERNAL: 'bg-amber-500', + RESTRICTED: 'bg-rose-500', +} + +const SCOPE_ACCENT: Record = { + PUBLIC: 'before:bg-emerald-500', + INTERNAL: 'before:bg-amber-500', + RESTRICTED: 'before:bg-rose-500', +} + function DictionariesPage() { const { t } = useTranslation() const navigate = useNavigate() @@ -41,6 +55,16 @@ function DictionariesPage() { return data.filter((d) => matchesQuery(d, q)) }, [data, deferredQuery]) + const groupedByScope = useMemo(() => { + const map: Record = { + PUBLIC: [], + INTERNAL: [], + RESTRICTED: [], + } + for (const d of filtered) map[d.scope].push(d) + return map + }, [filtered]) + const createButton = (