From ec99010697e8a2687d99ee01e2dc4751a62a8346 Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Mon, 11 May 2026 17:45:06 +0300 Subject: [PATCH] =?UTF-8?q?feat(editor):=20match=20redesign=20prototype=20?= =?UTF-8?q?layout=20=E2=80=94=20TopBar=20title=20+=20tab=20counts=20+=20In?= =?UTF-8?q?foPanel=20actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per /Users/zimin/Downloads/redesign/screens/03-editor-records.png редизайн prototype editor layout отличается от current MVP: 1. TopBar absorbs editor title + version (was в PageHeader) 2. PageHeader удалён — title и breadcrumb теперь только в TopBar 3. Tab labels получили counts (Записи 127, Связи 6, Поля 12) 4. Action buttons распределены per role: - Time-travel + AOI → InfoPanel bottom (close к data context) - Schema edit + +Запись → tab toolbar right (close к tab actions) Changes: src/components/layout/TopBar.tsx - Breadcrumb получил subtitle slot — mono ' · v' - useBreadcrumb fetches dict detail для editor route '/dictionaries/$name' - Render: '← Справочники / Космические аппараты satellites · v1.0.0' src/api/queries.ts - useDictionaryDetail принимает name: string | undefined + enabled flag - Guard для editor breadcrumb когда route не matches dict src/routes/dictionaries.$name.tsx - Removed — title/breadcrumb теперь в TopBar - EditorInfoPanel получает actions prop: onTimeTravel + timeTravelActive + onAoi + aoiActive - EditorTabBar получает counts (per-tab badge) + actions slot (right-aligned Schema + +Запись buttons) - extractOutgoingFkCount helper для relations count src/components/editor/EditorInfoPanel.tsx - actions prop с Time-travel + AOI buttons - Rendered в panel выше Relations section, между metadata и FK list - aria-pressed когда active (time-travel или AOI с filter) src/components/editor/EditorTabBar (inline in route) - counts prop: Partial> - actions prop: ReactNode для right-aligned cluster - inline count badge — text-mono text-mute next to label Tests: 116 pass. TS strict clean. --- ordinis-admin-ui/src/api/queries.ts | 3 +- .../src/components/editor/EditorInfoPanel.tsx | 50 +++++- .../src/components/layout/TopBar.tsx | 33 +++- .../src/routes/dictionaries.$name.tsx | 153 +++++++++--------- 4 files changed, 152 insertions(+), 87 deletions(-) diff --git a/ordinis-admin-ui/src/api/queries.ts b/ordinis-admin-ui/src/api/queries.ts index 3832ad0..40cab57 100644 --- a/ordinis-admin-ui/src/api/queries.ts +++ b/ordinis-admin-ui/src/api/queries.ts @@ -502,7 +502,8 @@ export const useLiveRecord = (dict: string | undefined, businessKey: string | un }) export const useDictionaries = () => useQuery(dictionariesQuery) -export const useDictionaryDetail = (name: string) => useQuery(dictionaryDetailQuery(name)) +export const useDictionaryDetail = (name: string | undefined) => + useQuery({ ...dictionaryDetailQuery(name ?? ''), enabled: Boolean(name) }) export const useRecords = ( dictionaryName: string, scopeCsv: string, diff --git a/ordinis-admin-ui/src/components/editor/EditorInfoPanel.tsx b/ordinis-admin-ui/src/components/editor/EditorInfoPanel.tsx index 092b192..664808a 100644 --- a/ordinis-admin-ui/src/components/editor/EditorInfoPanel.tsx +++ b/ordinis-admin-ui/src/components/editor/EditorInfoPanel.tsx @@ -1,9 +1,11 @@ import { useMemo } from 'react' import { Link } from '@tanstack/react-router' import { useTranslation } from 'react-i18next' +import { ClockCounterClockwiseIcon, MapTrifoldIcon } from '@phosphor-icons/react' import { Badge } from '@/ui' import { useDictionaryDependents } from '@/api/queries' import type { DictionaryDetail } from '@/api/client' +import { cn } from '@/lib/utils' /** * EditorInfoPanel — left rail с dict metadata per handoff prototype Screen 2. @@ -23,9 +25,17 @@ import type { DictionaryDetail } from '@/api/client' export type EditorInfoPanelProps = { detail: DictionaryDetail recordCount: number + /** Optional action buttons (Time-travel / AOI filter) — bottom of panel + * per redesign prototype. Toggle handlers come from route's state. */ + actions?: { + onTimeTravel?: () => void + timeTravelActive?: boolean + onAoi?: () => void + aoiActive?: boolean + } } -export function EditorInfoPanel({ detail, recordCount }: EditorInfoPanelProps) { +export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPanelProps) { const { t } = useTranslation() const { data: refByRaw } = useDictionaryDependents(detail.name) @@ -64,6 +74,44 @@ export function EditorInfoPanel({ detail, recordCount }: EditorInfoPanelProps) { + {/* Actions — bottom buttons per redesign prototype: Time-travel + AOI */} + {actions && ( +
+ {actions.onTimeTravel && ( + + )} + {actions.onAoi && ( + + )} +
+ )} + {/* Relations */} {(outgoingNames.length > 0 || incomingNames.length > 0) && (
void }) { )} - {/* Breadcrumb — left */} + {/* Breadcrumb — left. Editor route ('/dictionaries/$name') получает + * augmented breadcrumb с displayName + version (per redesign prototype). + * Остальные routes: regular path-based breadcrumb. */}