From cb8a229adfaedcbf48466c0793a6c6e5c244d9df Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Sat, 16 May 2026 00:09:41 +0300 Subject: [PATCH] =?UTF-8?q?fix(ui):=20QA=20report=20P3/P4=20batch=20?= =?UTF-8?q?=E2=80=94=207=20cosmetic/UX=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QA report cleanup (после P1/P2 ship'нутых в v2.31.4): - **BUG-009**: Excel/SQL export форматы получили явный «скоро» badge поверх opacity-only disabled state. Title attribute оставлен. - **BUG-010**: «Доступ актора» (audit scope column) переименован в «Scope» — компактнее, не переносится на 2 строки. - **BUG-011**: Все audit table headers получили title attribute → hover tooltip когда text truncate'ится («ИЗМЕНЕН…» → full «Изменения»). - **UX-001**: Scope chips в /dictionaries теперь показывают ✓ glyph когда selected → визуально clear что multi-select. Aria-label расширен: «Фильтр по области (можно выбрать несколько)». - **UX-002**: Breadcrumb segments получили title attribute → hover показывает full label когда truncate'ится в narrow viewport. - **UX-003**: При смене вкладки в редакторе справочника (records → relations и т.п.) URL params q/scopes сбрасываются — раньше search фильтр оставался применённым после возврата на records. - **UX-004**: TimeTravel slider boundary метки получили 2-digit year: «05.05.26» вместо «05.05» — disambiguates конец декабря / начало января. Title attribute exposes full локальную дату. - **UX-009**: «Удалить» button в RecordDrawer переименован в «Закрыть запись» — same action как row context menu «Закрыть» (bitemporal close, не truly delete). Consistent labeling across UI. --- .../src/components/editor/ExportModal.tsx | 10 ++++++++-- .../src/components/layout/TopBar.tsx | 7 ++++++- .../components/timetravel/TimeTravelModal.tsx | 14 ++++++++++++-- ordinis-admin-ui/src/i18n.ts | 12 ++++++------ ordinis-admin-ui/src/routes/audit.tsx | 17 +++++++++-------- .../src/routes/dictionaries.$name.tsx | 5 +++++ .../src/routes/dictionaries.index.tsx | 5 ++++- 7 files changed, 50 insertions(+), 20 deletions(-) diff --git a/ordinis-admin-ui/src/components/editor/ExportModal.tsx b/ordinis-admin-ui/src/components/editor/ExportModal.tsx index 8f6a99d..1b5fd1e 100644 --- a/ordinis-admin-ui/src/components/editor/ExportModal.tsx +++ b/ordinis-admin-ui/src/components/editor/ExportModal.tsx @@ -208,15 +208,21 @@ export function ExportModal({ disabled={f.disabled} title={f.reason} className={cn( - 'flex flex-col items-center justify-center gap-0.5 h-[68px] rounded-md border transition-colors', + 'relative flex flex-col items-center justify-center gap-0.5 h-[68px] rounded-md border transition-colors', format === f.id ? 'border-ink bg-surface text-ink ring-1 ring-ink' : 'border-line bg-surface text-ink-2 hover:border-line-2 hover:bg-surface-2', - f.disabled && 'opacity-40 cursor-not-allowed hover:bg-surface hover:border-line', + f.disabled && 'opacity-60 cursor-not-allowed hover:bg-surface hover:border-line', )} > {f.label} {f.ext} + {/* QA BUG-009: явный «скоро» badge вместо опоры только на opacity. */} + {f.disabled && ( + + {t('export.format.soon', { defaultValue: 'скоро' })} + + )} ))} diff --git a/ordinis-admin-ui/src/components/layout/TopBar.tsx b/ordinis-admin-ui/src/components/layout/TopBar.tsx index 413307f..e7d0a9d 100644 --- a/ordinis-admin-ui/src/components/layout/TopBar.tsx +++ b/ordinis-admin-ui/src/components/layout/TopBar.tsx @@ -48,9 +48,11 @@ export function TopBar({ onMenuClick }: { onMenuClick?: () => void }) { return ( {i > 0 && /} + {/* QA UX-002: title attribute → hover tooltip когда truncate. */} {crumb.to && !isLast ? ( void }) { {crumb.label} ) : ( - + {crumb.label} )} diff --git a/ordinis-admin-ui/src/components/timetravel/TimeTravelModal.tsx b/ordinis-admin-ui/src/components/timetravel/TimeTravelModal.tsx index 86547ba..dc1fc74 100644 --- a/ordinis-admin-ui/src/components/timetravel/TimeTravelModal.tsx +++ b/ordinis-admin-ui/src/components/timetravel/TimeTravelModal.tsx @@ -571,9 +571,15 @@ function TimelineSlider({ * чтобы две DD.MM метки ~ 36px @ text-cap не пересекались на типичной * ширине трека ~340px. */}
+ {/* QA UX-004: добавлен 2-digit year к boundary меткам — раньше «05.05» + * без года был неоднозначным на конец декабря / начало января. */} {pct > 12 && ( - + {new Date(range.min).toLocaleDateString(undefined, { + year: '2-digit', month: '2-digit', day: '2-digit', })} @@ -586,8 +592,12 @@ function TimelineSlider({ {dateLabel} {pct < 88 && ( - + {new Date(range.max).toLocaleDateString(undefined, { + year: '2-digit', month: '2-digit', day: '2-digit', })} diff --git a/ordinis-admin-ui/src/i18n.ts b/ordinis-admin-ui/src/i18n.ts index 49b4f22..54d07e6 100644 --- a/ordinis-admin-ui/src/i18n.ts +++ b/ordinis-admin-ui/src/i18n.ts @@ -278,7 +278,7 @@ i18n // User confusion: 'правки в public были, а тут RESTRICTED' — // потому что у пользователя scope=RESTRICTED привилегия. Label // 'Доступ актора' разъясняет это. - 'audit.col.scope': 'Доступ актора', + 'audit.col.scope': 'Scope', 'audit.col.trace': 'Trace', 'audit.col.diff': 'Изменения', 'audit.action.expand': 'Раскрыть', @@ -334,7 +334,7 @@ i18n 'dict.list.deps.short': 'СО СВЯЗЯМИ', // Catalog v2 (URL-driven filters + sort + density) 'dict.list.heading': 'Каталог справочников', - 'dict.list.filter.scope': 'Фильтр по области', + 'dict.list.filter.scope': 'Фильтр по области (можно выбрать несколько)', 'dict.list.sort.label': 'Сортировка', 'dict.list.sort.name': 'По названию', 'dict.list.sort.recordCount': 'По количеству записей', @@ -424,7 +424,7 @@ i18n 'form.cancel': 'Отмена', 'form.save': 'Сохранить', 'form.saving': 'Сохранение...', - 'form.delete': 'Удалить', + 'form.delete': 'Закрыть запись', 'form.error.required': 'Обязательное поле', 'form.unsavedNFields_one': 'не сохранено · {{count}} поле', 'form.unsavedNFields_few': 'не сохранено · {{count}} поля', @@ -1103,7 +1103,7 @@ i18n 'audit.col.dictionary': 'Dictionary', 'audit.col.businessKey': 'Business key', 'audit.col.user': 'User', - 'audit.col.scope': 'Actor scope', + 'audit.col.scope': 'Scope', 'audit.col.trace': 'Trace', 'audit.col.diff': 'Diff', 'audit.action.expand': 'Expand', @@ -1157,7 +1157,7 @@ i18n 'dict.list.deps.short': 'WITH LINKS', // Catalog v2 'dict.list.heading': 'Dictionary catalog', - 'dict.list.filter.scope': 'Scope filter', + 'dict.list.filter.scope': 'Scope filter (multi-select)', 'dict.list.sort.label': 'Sort', 'dict.list.sort.name': 'By name', 'dict.list.sort.recordCount': 'By record count', @@ -1239,7 +1239,7 @@ i18n 'form.cancel': 'Cancel', 'form.save': 'Save', 'form.saving': 'Saving...', - 'form.delete': 'Delete', + 'form.delete': 'Close record', 'form.unsavedNFields_one': 'unsaved · {{count}} field', 'form.unsavedNFields_other': 'unsaved · {{count}} fields', 'drawer.collapse': 'Collapse to 520px', diff --git a/ordinis-admin-ui/src/routes/audit.tsx b/ordinis-admin-ui/src/routes/audit.tsx index 948d07f..efee47f 100644 --- a/ordinis-admin-ui/src/routes/audit.tsx +++ b/ordinis-admin-ui/src/routes/audit.tsx @@ -441,14 +441,15 @@ function AuditTable({ rows }: { rows: AuditEntry[] }) { - {t('audit.col.time')} - {t('audit.col.action')} - {t('audit.col.dictionary')} - {t('audit.col.businessKey')} - {t('audit.col.user')} - {t('audit.col.scope')} - {t('audit.col.trace')} - {t('audit.col.diff')} + {/* QA BUG-011 fix: title attribute → hover tooltip когда text truncate'ится. */} + {t('audit.col.time')} + {t('audit.col.action')} + {t('audit.col.dictionary')} + {t('audit.col.businessKey')} + {t('audit.col.user')} + {t('audit.col.scope')} + {t('audit.col.trace')} + {t('audit.col.diff')} diff --git a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx index a5739a2..6e3fe8e 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx @@ -839,6 +839,11 @@ function DictionaryDetail() { search: (prev) => ({ ...prev, tab: tab === 'records' ? undefined : tab, + // QA UX-003: сбросить records-tab фильтры (search/q + column filters + // + scopes) когда пользователь перешёл на другую вкладку. Иначе + // search:'абв' оставался применённым после возврата на records. + q: undefined, + scopes: undefined, }), replace: true, }) diff --git a/ordinis-admin-ui/src/routes/dictionaries.index.tsx b/ordinis-admin-ui/src/routes/dictionaries.index.tsx index c06a4fb..ab7297f 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.index.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.index.tsx @@ -281,12 +281,15 @@ function DictionariesPage() { // Scope chips всегда покрашены в свой scope-color (filled bg // + colored text) per user feedback ("плашки то покрась"). // Selected state — ring-1 ring-{scope} + slightly opaque bg. - className={`h-8 text-cap tracking-[0.14em] uppercase font-semibold px-2.5 rounded-md border inline-flex items-center transition-all focus:outline-none focus:ring-2 focus:ring-accent/40 ${SCOPE_BG_TINT[scope]} ${SCOPE_TEXT[scope]} ${ + // QA UX-001: ✓ glyph когда selected — clarifies что это + // multi-select (checkbox-like), не radio. + className={`h-8 text-cap tracking-[0.14em] uppercase font-semibold px-2.5 rounded-md border inline-flex items-center gap-1 transition-all focus:outline-none focus:ring-2 focus:ring-accent/40 ${SCOPE_BG_TINT[scope]} ${SCOPE_TEXT[scope]} ${ selected ? `border-current shadow-sm` : 'border-transparent opacity-70 hover:opacity-100' }`} > + {selected && } {scope} )