mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 09:08:54 -04:00
fix(ui): stop the add-on shell drawing a title over add-on pages
The app decides what its page shows. The shell drew the add-on name as a header above every add-on page, so an add-on could not choose its own title. The shell now draws no header on a live, loading or frozen add-on page; each add-on titles its own pages. The unavailable and missing-page states keep the name, because no add-on page is drawn there. The runtime and shell specs now check that the shell adds no page title. Assisted-by: Claude Code:claude-sonnet-5-5 node playwright Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
3 files changed
+17
-13
No files matched your search
@@ -88,7 +88,8 @@ test.describe('Add-on UI runtime', () => {
|
||||
await expect(surface(page)).toBeVisible({ timeout: 20_000 })
|
||||
await expect(page.getByTestId('fx-title')).toHaveText('Hello fixture')
|
||||
await expect(page.getByTestId('fx-where')).toHaveText('page=home path=')
|
||||
await expect(page.locator('h1.page-title')).toHaveText('UI fixture')
|
||||
// The shell draws no title over the page: the add-on draws its own.
|
||||
await expect(page.locator('h1.page-title')).toHaveCount(0)
|
||||
// Every file came from the owner through the asset route, under one digest.
|
||||
const js = answers.find(a => a.url.endsWith('/ui.js'))
|
||||
const css = answers.find(a => a.url.endsWith('/ui/style.css'))
|
||||
@@ -142,8 +143,9 @@ test.describe('Add-on UI runtime', () => {
|
||||
return {
|
||||
sheet: document.querySelector('style[data-addon-style="uifixture"]')?.textContent || '',
|
||||
title: style(document.querySelector('[data-testid="fx-title"]')).color,
|
||||
hostTitle: style(document.querySelector('h1.page-title')).color,
|
||||
hostTitleSize: style(document.querySelector('h1.page-title')).fontSize,
|
||||
hostNavColor: style(document.querySelector('.sidebar-nav a, .sidebar-nav button')).color,
|
||||
hostNavSize: style(document.querySelector('.sidebar-nav a, .sidebar-nav button')).fontSize,
|
||||
shellTitles: document.querySelectorAll('h1.page-title').length,
|
||||
bodyBackground: style(document.body).backgroundColor,
|
||||
token: style(root).getPropertyValue('--fx-token').trim(),
|
||||
rootToken: style(document.documentElement).getPropertyValue('--fx-token').trim(),
|
||||
@@ -151,8 +153,9 @@ test.describe('Add-on UI runtime', () => {
|
||||
}
|
||||
})
|
||||
expect(probe.title).toBe('rgb(1, 2, 3)')
|
||||
expect(probe.hostTitle).not.toBe('rgb(255, 0, 0)')
|
||||
expect(probe.hostTitleSize).not.toBe('11px')
|
||||
expect(probe.shellTitles).toBe(0)
|
||||
expect(probe.hostNavColor).not.toBe('rgb(255, 0, 0)')
|
||||
expect(probe.hostNavSize).not.toBe('11px')
|
||||
expect(probe.bodyBackground).not.toBe('rgb(255, 0, 255)')
|
||||
expect(probe.token).toBe('1')
|
||||
expect(probe.rootToken).toBe('')
|
||||
@@ -173,8 +176,8 @@ test.describe('Add-on UI runtime', () => {
|
||||
await expect(card).toBeVisible({ timeout: 20_000 })
|
||||
await expect(card).toContainText('This add-on had a problem')
|
||||
await shoot(page, 'esm-error-boundary')
|
||||
// The page header, the sidebar and the other routes are untouched.
|
||||
await expect(page.locator('h1.page-title')).toHaveText('UI fixture')
|
||||
// The sidebar and the other routes are untouched, and the shell adds no title.
|
||||
await expect(page.locator('h1.page-title')).toHaveCount(0)
|
||||
await expect(page.locator('.sidebar-nav')).toBeVisible()
|
||||
await page.goto('/app/addons/uifixture/home')
|
||||
await expect(page.getByTestId('fx-title')).toBeVisible({ timeout: 20_000 })
|
||||
@@ -328,7 +331,7 @@ test.describe('Add-on UI runtime', () => {
|
||||
// The router error page never replaces the host.
|
||||
await expect(page.getByText('Unexpected Application Error')).toHaveCount(0)
|
||||
await expect(page.locator('.sidebar-nav')).toBeVisible()
|
||||
await expect(page.locator('h1.page-title')).toHaveText('UI fixture')
|
||||
await expect(page.locator('h1.page-title')).toHaveCount(0)
|
||||
await layer.getByRole('button', { name: 'Close' }).last().click()
|
||||
await expect(layer).toHaveCount(0)
|
||||
}
|
||||
|
||||
@@ -46,8 +46,10 @@ test.describe('Add-on shell', () => {
|
||||
await expect(page.getByTestId('fx-title')).toHaveText('Hello fixture')
|
||||
await page.getByRole('button', { name: 'Increment' }).click()
|
||||
await expect(surface.getByText('hooks 1')).toBeVisible()
|
||||
// The sheet's `h1` rule never reaches the host's own page title.
|
||||
await expect(page.locator('h1.page-title')).not.toHaveCSS('font-size', '11px')
|
||||
// The shell draws no title over the add-on page, and the sheet's `h1`
|
||||
// rule never reaches the host's own chrome.
|
||||
await expect(page.locator('h1.page-title')).toHaveCount(0)
|
||||
await expect(page.locator('.sidebar-nav a, .sidebar-nav button').first()).not.toHaveCSS('font-size', '11px')
|
||||
await expect(page.locator('style[data-addon-style="uifixture"]')).toHaveCount(1)
|
||||
// The detail view of the add-on links the declared navigation page.
|
||||
await page.goto('/app/addons?detail=uifixture')
|
||||
|
||||
@@ -154,7 +154,7 @@ export default function AddonRoute() {
|
||||
if (registry.status === 'idle' || (registry.status === 'error' && !app)) {
|
||||
if (registry.status === 'error') return unavailable('import_failed', reloadButton)
|
||||
return (
|
||||
<div className="page ad-page" data-testid="addon-loading"><PageHeader title={title} /><LoadingSpinner /></div>
|
||||
<div className="page ad-page" data-testid="addon-loading"><LoadingSpinner /></div>
|
||||
)
|
||||
}
|
||||
const isStale = Boolean(instance && instance.status === 'stale')
|
||||
@@ -184,7 +184,6 @@ export default function AddonRoute() {
|
||||
if (!instance || instance.status === 'loading') {
|
||||
return (
|
||||
<div className="page ad-page" data-testid="addon-loading">
|
||||
<PageHeader title={title} />
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
)
|
||||
@@ -193,7 +192,7 @@ export default function AddonRoute() {
|
||||
// survives the moment it is withdrawn.
|
||||
return (
|
||||
<div className="page ad-page" data-testid={isStale ? 'addon-stale' : 'addon-page'}>
|
||||
<PageHeader title={title} />
|
||||
{/* The add-on draws its own title; the shell adds none. */}
|
||||
{isStale && (
|
||||
<div className="ad-banner" role="alert">
|
||||
<span>{t('shell.stale', { title })}</span>
|
||||
|
||||
Reference in new issue
Block a user