feat(quick-261016-nqk): admin heads form and preview with meta.title (G-18.1-4)
This commit is contained in:
@@ -78,6 +78,8 @@ const recordId = mode === 'update' ? Number(route.params.id) : null
|
||||
const schema = ref<FormView | null>(null)
|
||||
const values = ref<AdminRecord>({})
|
||||
const labels = ref<RecordMeta['labels']>({})
|
||||
/** The controller's record title (meta.title, pact.FormRecordTitle); '' when it names none. */
|
||||
const recordTitle = ref('')
|
||||
const errors = ref<Record<string, string[]>>({})
|
||||
// The text of a save the server refused with 403 (UI-SPEC S6). It is a
|
||||
// banner, not a toast: it stays readable until the next save attempt.
|
||||
@@ -157,9 +159,11 @@ const panelFields = computed(() => {
|
||||
return fields.value.filter((field) => tabOf(field) === key)
|
||||
})
|
||||
|
||||
/** 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)),
|
||||
/** The record's display name: the controller's title, else the first text-like field's value, in schema order. */
|
||||
const recordName = computed(
|
||||
() =>
|
||||
recordTitle.value ||
|
||||
recordDisplayName(schema.value?.fields, values.value, schemaEnabledLocales(schema.value?.meta)),
|
||||
)
|
||||
|
||||
const title = computed(() => {
|
||||
@@ -217,6 +221,7 @@ function adopt(record: RecordEnvelope | undefined): void {
|
||||
}
|
||||
values.value = next
|
||||
labels.value = record.meta.labels ?? {}
|
||||
recordTitle.value = record.meta.title ?? ''
|
||||
}
|
||||
saved.value = snapshot(editablePayload(fields.value, values.value, mode))
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ const recordPath = `${listPath}/${recordId}`
|
||||
const schema = ref<FormView | null>(null)
|
||||
const values = ref<AdminRecord>({})
|
||||
const labels = ref<RecordMeta['labels']>({})
|
||||
/** The controller's record title (meta.title, pact.FormRecordTitle); '' when it names none. */
|
||||
const recordTitle = ref('')
|
||||
const actions = ref<RecordAction[]>([])
|
||||
const loading = ref(true)
|
||||
const failed = ref(false)
|
||||
@@ -112,9 +114,11 @@ const panelFields = computed(() => {
|
||||
return fields.value.filter((field) => tabOf(field) === key)
|
||||
})
|
||||
|
||||
/** 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)),
|
||||
/** The record's display name: the controller's title, else the first text-like field's value, in schema order. */
|
||||
const recordName = computed(
|
||||
() =>
|
||||
recordTitle.value ||
|
||||
recordDisplayName(schema.value?.fields, values.value, schemaEnabledLocales(schema.value?.meta)),
|
||||
)
|
||||
|
||||
const subtitle = computed(() => message(schema.value?.messages.preview, undefined, { name: recordName.value }))
|
||||
@@ -146,6 +150,7 @@ async function loadRecord(): Promise<boolean> {
|
||||
}
|
||||
values.value = { ...result.data.data }
|
||||
labels.value = result.data.meta.labels ?? {}
|
||||
recordTitle.value = result.data.meta.title ?? ''
|
||||
actions.value = result.data.meta.actions ?? []
|
||||
return true
|
||||
} catch {
|
||||
|
||||
@@ -623,6 +623,14 @@ describe('password and preset on the form (UI-SPEC S7, D-19, D-27 G7)', () => {
|
||||
expect(editor(wrapper, 'slug').element.value).toBe('ada-lovelace')
|
||||
})
|
||||
|
||||
it("titles a record by the controller's meta.title when it sends one, and publishes it as the crumb", async () => {
|
||||
const record = clone(rosterRecordFixture)
|
||||
;(record.meta as { title?: string }).title = 'Person #1 (Ada)'
|
||||
const { wrapper } = await mountApp('/acme/roster/people/1', people({ [`GET ${PERSON}`]: { body: record } }))
|
||||
expect(wrapper.find('h1').text()).toBe('Person #1 (Ada)')
|
||||
expect(recordCrumb.value).toBe('Person #1 (Ada)')
|
||||
})
|
||||
|
||||
it('titles a record by the default locale of an mltext first field, and publishes it as the crumb', async () => {
|
||||
const record = clone(rosterRecordFixture)
|
||||
record.data.name = { en: 'Ada Lovelace', pl: 'Ada Lovelace PL' }
|
||||
|
||||
@@ -139,6 +139,19 @@ describe('preview view (UI-SPEC S3, D-11)', () => {
|
||||
expect(recordCrumb.value).toBe('Ada Lovelace')
|
||||
})
|
||||
|
||||
it("heads the record by the controller's meta.title when it sends one, before the first text field", async () => {
|
||||
const { wrapper } = await mountApp(
|
||||
PREVIEW,
|
||||
routes({
|
||||
[`GET ${RECORD}`]: recordWith((record) => {
|
||||
;(record.meta as { title?: string }).title = 'Person #1 (Ada)'
|
||||
}),
|
||||
}),
|
||||
)
|
||||
expect(wrapper.find('h1').text()).toBe('Person #1 (Ada)')
|
||||
expect(recordCrumb.value).toBe('Person #1 (Ada)')
|
||||
})
|
||||
|
||||
it('shows the muted dash for an empty value and the label of a relation, never its id', async () => {
|
||||
const { wrapper } = await mountApp(PREVIEW, routes({ [`GET ${RECORD}`]: recordWith((record) => (record.data.joined_ip = null)) }))
|
||||
expect(wrapper.find('[data-preview-field="joined_ip"] [data-empty]').text()).toBe('—')
|
||||
|
||||
Reference in New Issue
Block a user