feat(admin): open controller-link settings entries from the settings index
A settings entry with a controller opens that controller's route from its card (settingsPath); singleton cards still open /settings/<code>. On a linked controller with no navigation entry of its own the rail marks Settings current, the breadcrumbs read Settings > entry label (plus the record title on record and create routes) and the page title uses the entry label. The settings docs describe the admin behaviour; the embedded admin shell is rebuilt.
This commit is contained in:
@@ -33,6 +33,17 @@ describe('documentTitleForRoute', () => {
|
||||
expect(documentTitleForRoute((await routerAt('/settings/mail')).currentRoute.value)).toBe('Mail | SummerCMS')
|
||||
})
|
||||
|
||||
it('uses the settings entry label on a settings-linked controller', async () => {
|
||||
await signIn()
|
||||
setNavigation(navigationFixture.data)
|
||||
const locales = { ...settingsFixture.list.data[0]!, code: 'locales', label: 'Locales', model: '', controller: 'acme.lang.locales' }
|
||||
setSettings([...settingsFixture.list.data, locales])
|
||||
expect(documentTitleForRoute((await routerAt('/acme/lang/locales')).currentRoute.value)).toBe('Locales | SummerCMS')
|
||||
expect(documentTitleForRoute((await routerAt('/acme/lang/locales/3')).currentRoute.value)).toBe('Locales | SummerCMS')
|
||||
setRecordCrumb('Polish')
|
||||
expect(documentTitleForRoute((await routerAt('/acme/lang/locales/3')).currentRoute.value)).toBe('Polish | SummerCMS')
|
||||
})
|
||||
|
||||
it('uses translated indicators for login, the empty home and not found', async () => {
|
||||
expect(documentTitleForRoute((await routerAt('/login')).currentRoute.value)).toBe('Witaj ponownie | SummerCMS')
|
||||
await signIn()
|
||||
|
||||
@@ -53,6 +53,14 @@ describe('settings index (D-21)', () => {
|
||||
expect(link.text()).toBe('Search')
|
||||
expect(wrapper.find('[data-settings-group] h2').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('opens a controller-link entry on its controller route and keeps singleton links', async () => {
|
||||
const link = { ...settingsFixture.list.data[0]!, code: 'locales', label: 'Locales', model: '', controller: 'acme.demo.locales' }
|
||||
setSettings([...settingsFixture.list.data, link])
|
||||
const { wrapper } = await mountApp('/settings', routes())
|
||||
expect(wrapper.find('[data-settings="locales"]').attributes('href')).toMatch(/\/acme\/demo\/locales$/)
|
||||
expect(wrapper.find('[data-settings="mail"]').attributes('href')).toBe('/settings/mail')
|
||||
})
|
||||
})
|
||||
|
||||
describe('settings form (D-21)', () => {
|
||||
|
||||
@@ -72,6 +72,37 @@ describe('breadcrumbs', () => {
|
||||
expect((await crumbsAt('/settings/unknown')).labels).toEqual(['Ustawienia'])
|
||||
})
|
||||
|
||||
it('reads Ustawienia and the entry label on a settings-linked controller', async () => {
|
||||
const locales = { ...settingsFixture.list.data[0]!, code: 'locales', label: 'Locales', model: '', controller: 'acme.lang.locales' }
|
||||
const crumbsWithLink = async (path: string) => {
|
||||
await signIn()
|
||||
setNavigation(navigationFixture.data)
|
||||
setSettings([...settingsFixture.list.data, locales])
|
||||
const router = await routerAt(path)
|
||||
const wrapper = mount(Breadcrumbs, { global: { plugins: [router] } })
|
||||
await flushPromises()
|
||||
const items = wrapper.findAll('[data-crumb]')
|
||||
return {
|
||||
labels: items.map((item) => item.text()),
|
||||
links: items.map((item) => (item.find('a').exists() ? item.find('a').attributes('href') : null)),
|
||||
current: items.map((item) => item.find('[aria-current="page"]').exists()),
|
||||
}
|
||||
}
|
||||
let crumbs = await crumbsWithLink('/acme/lang/locales')
|
||||
expect(crumbs.labels).toEqual(['Ustawienia', 'Locales'])
|
||||
expect(crumbs.links).toEqual(['/settings', null])
|
||||
expect(crumbs.current).toEqual([false, true])
|
||||
|
||||
setRecordCrumb('Polish')
|
||||
crumbs = await crumbsWithLink('/acme/lang/locales/3')
|
||||
expect(crumbs.labels).toEqual(['Ustawienia', 'Locales', 'Polish'])
|
||||
expect(crumbs.links).toEqual(['/settings', '/acme/lang/locales', null])
|
||||
|
||||
setRecordCrumb('')
|
||||
crumbs = await crumbsWithLink('/acme/lang/locales/create')
|
||||
expect(crumbs.labels).toEqual(['Ustawienia', 'Locales'])
|
||||
})
|
||||
|
||||
it('is empty outside any permitted plugin', async () => {
|
||||
expect((await crumbsAt('/acme/secret/things')).labels).toEqual([])
|
||||
expect((await crumbsAt('/acme/demo/unlisted')).labels).toEqual(['Demo'])
|
||||
|
||||
@@ -59,6 +59,20 @@ describe('plugin rail', () => {
|
||||
expect(link.attributes('aria-current')).toBe('page')
|
||||
})
|
||||
|
||||
it('marks Ustawienia current on a settings-linked controller without a navigation entry', async () => {
|
||||
const locales = { ...settingsFixture.list.data[0]!, code: 'locales', label: 'Locales', model: '', controller: 'acme.lang.locales' }
|
||||
const widgets = { ...locales, code: 'widgets', label: 'Widgets', controller: 'acme.demo.widgets' }
|
||||
setSettings([...settingsFixture.list.data, locales, widgets])
|
||||
const { wrapper } = await mountRail('/acme/lang/locales')
|
||||
expect(wrapper.find('[data-rail-settings]').attributes('aria-current')).toBe('page')
|
||||
expect(wrapper.findAll('[data-rail-item][aria-current="page"]')).toHaveLength(0)
|
||||
|
||||
// A linked controller that also has a navigation entry keeps its plugin.
|
||||
const nav = await mountRail('/acme/demo/widgets')
|
||||
expect(nav.wrapper.find('[data-rail-settings]').attributes('aria-current')).toBeUndefined()
|
||||
expect(nav.wrapper.find('[data-rail-item="demo"]').attributes('aria-current')).toBe('page')
|
||||
})
|
||||
|
||||
it('offers menu semantics and the expand button after a manual collapse', async () => {
|
||||
const { wrapper } = await mountRail('/acme/demo/widgets')
|
||||
expect(wrapper.find('[data-sidebar-expand]').exists()).toBe(false)
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
settings,
|
||||
settingsEntry,
|
||||
settingsGroups,
|
||||
settingsLinkFor,
|
||||
settingsPath,
|
||||
useSettings,
|
||||
} from '../../src/state/useSettings'
|
||||
import { settingsFixture } from '../fixtures/typed'
|
||||
@@ -44,4 +46,22 @@ describe('useSettings (D-21)', () => {
|
||||
['System', ['mail', 'search']],
|
||||
])
|
||||
})
|
||||
|
||||
it('links a singleton to its form and a controller link to the controller route', () => {
|
||||
const singleton = settingsFixture.list.data[0]!
|
||||
expect(settingsPath({ ...singleton, code: 'a b' })).toBe('/settings/a%20b')
|
||||
expect(settingsPath({ ...singleton, code: 'locales', model: '', controller: 'acme.demo.locales' })).toBe('/acme/demo/locales')
|
||||
expect(settingsPath({ ...singleton, code: 'broken', model: '', controller: 'acme.demo' })).toBe('/settings')
|
||||
expect(useSettings().settingsPath).toBe(settingsPath)
|
||||
})
|
||||
|
||||
it('finds the link entry that opens a controller, never a singleton', () => {
|
||||
const link = { ...settingsFixture.list.data[0]!, code: 'locales', model: '', controller: 'acme.demo.locales' }
|
||||
setSettings([...settingsFixture.list.data, link])
|
||||
expect(settingsLinkFor('acme.demo.locales')?.code).toBe('locales')
|
||||
expect(settingsLinkFor('acme.demo.widgets')).toBeNull()
|
||||
expect(settingsLinkFor('')).toBeNull()
|
||||
expect(settingsLinkFor(null)).toBeNull()
|
||||
expect(useSettings().settingsLinkFor).toBe(settingsLinkFor)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user