fix(dict): name column в records list — pick localized value, не [object Object]

Раньше для записей с x-localized name (КА, антенна, ground_station,
operator) колонка 'name / code' показывала literal '[object Object]'
потому что String({'ru-RU': 'Канопус', 'en-US': 'Kanopus'}) =
toString() стандартный → '[object Object]'.

Решение:
- Новый shared util lib/locales.ts:
  - pickLocalized(value, defaultLocale) — извлекает строку из i18n
    объекта или plain string. Fallback на first non-empty key
    если defaultLocale не найден.
  - recordDisplayName(data, defaultLocale) — name → code → '—' chain.
- Records list использует recordDisplayName с dict.defaultLocale
  (берётся из DictionaryDetail).
- SchemaDrivenForm дедуплицирован — был свой локальный pickLocalized,
  теперь импортирует из util'ы.

Tests: +13 (76 → 89), unit tests на pickLocalized + recordDisplayName
покрывают все edge cases (plain string, localized object, fallback
chain, null/undefined input).
This commit is contained in:
Zimin A.N.
2026-05-06 21:05:50 +03:00
parent 66e89ce707
commit 5e1b39db03
4 changed files with 124 additions and 17 deletions
@@ -29,6 +29,7 @@ import {
formatIsoDate,
parseFormDate,
} from '@/lib/dates'
import { pickLocalized } from '@/lib/locales'
type FormValues = {
businessKey: string
@@ -823,22 +824,6 @@ const buildOption = (
return { id: idStr, label }
}
const pickLocalized = (
value: unknown,
defaultLocale: string,
): string | undefined => {
if (typeof value === 'string') return value
if (!value || typeof value !== 'object') return undefined
const map = value as Record<string, unknown>
const direct = map[defaultLocale]
if (typeof direct === 'string' && direct.length > 0) return direct
for (const key of Object.keys(map)) {
const v = map[key]
if (typeof v === 'string' && v.length > 0) return v
}
return undefined
}
const countErrorsPerTab = (
errors: ReturnType<typeof useForm<FormValues>>['formState']['errors'],
buckets: Record<TabId, string[]>,