fix(admin): name records by translatable (mltext) fields
The record heading, breadcrumb crumb and document title took the first plain text field only, so records named by an mltext field fell back to the generic update message. A shared recordDisplayName helper now takes the first text or ML field and reads its default locale, then the first non-empty one.
This commit is contained in:
@@ -217,6 +217,35 @@ export function mergeMLValue(incoming: unknown, enabledLocales: readonly string[
|
||||
return { ...seeded, ...localeRecord(incoming) }
|
||||
}
|
||||
|
||||
/** The record's display name: the value of the first text-like field (plain
|
||||
* `text` or an ML type) in schema order. An ML value reads the default (first
|
||||
* enabled) locale, then the first non-empty locale; '' when nothing is set. */
|
||||
export function recordDisplayName(
|
||||
fields: readonly FormField[] | undefined,
|
||||
values: AdminRecord,
|
||||
enabledLocales: readonly string[],
|
||||
): string {
|
||||
const first = fields?.find((field) => field.type === 'text' || isMLFieldType(field.type))
|
||||
const value = first ? values[first.name] : undefined
|
||||
if (typeof value === 'string' || typeof value === 'number') {
|
||||
return String(value).trim()
|
||||
}
|
||||
if (!first || !isMLFieldType(first.type)) {
|
||||
return ''
|
||||
}
|
||||
const texts = localeRecord(value)
|
||||
const preferred = enabledLocales[0] !== undefined ? (texts[enabledLocales[0]] ?? '').trim() : ''
|
||||
if (preferred !== '') {
|
||||
return preferred
|
||||
}
|
||||
for (const text of Object.values(texts)) {
|
||||
if (text.trim() !== '') {
|
||||
return text.trim()
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/** D-10 422 details (field -> messages) as a string-list map. */
|
||||
export function fieldErrors(details: ErrorBody['details'] | undefined): Record<string, string[]> {
|
||||
const out: Record<string, string[]> = {}
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
mergeMLValue,
|
||||
panelDomId,
|
||||
presetUpdates,
|
||||
recordDisplayName,
|
||||
schemaEnabledLocales,
|
||||
snapshot,
|
||||
tabDomId,
|
||||
@@ -139,12 +140,10 @@ const panelFields = computed(() => {
|
||||
return fields.value.filter((field) => tabOf(field) === key)
|
||||
})
|
||||
|
||||
/** The record's display name: the first text field's value, in schema order. */
|
||||
const recordName = computed(() => {
|
||||
const first = schema.value?.fields.find((field) => field.type === 'text')
|
||||
const value = first ? values.value[first.name] : undefined
|
||||
return typeof value === 'string' || typeof value === 'number' ? String(value).trim() : ''
|
||||
})
|
||||
/** The record's display name: the first text-like field's value, in schema order. */
|
||||
const recordName = computed(() =>
|
||||
recordDisplayName(schema.value?.fields, values.value, schemaEnabledLocales(schema.value?.meta)),
|
||||
)
|
||||
|
||||
const title = computed(() => {
|
||||
if (mode === 'update' && recordName.value !== '') {
|
||||
|
||||
@@ -14,7 +14,16 @@ import FormTabs from '../components/form/FormTabs.vue'
|
||||
import PreviewField from '../components/form/PreviewField.vue'
|
||||
import RecordActions from '../components/form/RecordActions.vue'
|
||||
import { RELATION_MANAGER } from '../components/form/registry'
|
||||
import { DEFAULT_TAB, contextAllows, panelDomId, tabDomId, tabOf, type TabItem } from '../components/form/formState'
|
||||
import {
|
||||
DEFAULT_TAB,
|
||||
contextAllows,
|
||||
panelDomId,
|
||||
recordDisplayName,
|
||||
schemaEnabledLocales,
|
||||
tabDomId,
|
||||
tabOf,
|
||||
type TabItem,
|
||||
} from '../components/form/formState'
|
||||
import PartialHost from '../components/partial/PartialHost.vue'
|
||||
import Button from '../components/ui/Button.vue'
|
||||
import { clearRecordCrumb, setRecordCrumb } from '../state/useBreadcrumbs'
|
||||
@@ -96,12 +105,10 @@ const panelFields = computed(() => {
|
||||
return fields.value.filter((field) => tabOf(field) === key)
|
||||
})
|
||||
|
||||
/** The record's display name: the first text field's value, in schema order. */
|
||||
const recordName = computed(() => {
|
||||
const first = schema.value?.fields.find((field) => field.type === 'text')
|
||||
const value = first ? values.value[first.name] : undefined
|
||||
return typeof value === 'string' || typeof value === 'number' ? String(value).trim() : ''
|
||||
})
|
||||
/** The record's display name: the first text-like field's value, in schema order. */
|
||||
const recordName = computed(() =>
|
||||
recordDisplayName(schema.value?.fields, values.value, schemaEnabledLocales(schema.value?.meta)),
|
||||
)
|
||||
|
||||
const subtitle = computed(() => message(schema.value?.messages.preview, undefined, { name: recordName.value }))
|
||||
const hintPartial = computed(() => schema.value?.preview?.headerPartial ?? '')
|
||||
|
||||
Reference in New Issue
Block a user