Files
LocalAI/core/http/react-ui/e2e/navigation.spec.js
T
mudler's LocalAI [bot]andEttore Di Giacinto 0aaff91ebd feat(ui): unify model and backend lifecycle (#11548)
* feat(ui): add installed model lifecycle

Models now owns catalog exploration and installed runtime controls under one canonical route. URL-owned state keeps lifecycle context recoverable through links and browser history.

Assisted-by: Codex:gpt-5 Playwright

* feat(ui): add installed backend lifecycle

Backends split discovery from backend-binary management. The canonical
page now keeps both lifecycle views under one URL-backed shell while it
preserves target-node placement.

Assisted-by: Codex:gpt-5 Playwright

* fix(ui): repair lifecycle state updates

Installed models lost distributed refreshes and kept a deleted selection. Backend searches also stopped tracking URL changes, while batch upgrades stopped after their first error.

Preserve background refreshes and finish each requested batch action. Drive catalog results from URL-backed state without losing full metadata.

Assisted-by: Codex:gpt-5 [Playwright]

* feat(ui): make resource pages canonical

Replace Host navigation with canonical Models and Backends lifecycle routes, preserve legacy management URLs, and surface shared host capacity on the Operate overview.

Assisted-by: Codex:gpt-5 [Playwright]

* feat(ui): complete canonical resource lifecycle

Finish the responsive list-to-detail behavior, remove the retired Host implementation, and keep Explore focused on discovery while Installed owns destructive actions. Update regression coverage, localization, documentation, and development binding for the canonical resource pages.

Assisted-by: Codex:gpt-5 [Playwright]

* docs(ui): record the UI design context

Record the approved users, brand character, and design principles so
future interface work uses the same product direction. Index the context
from the repository's agent instructions.

Assisted-by: Codex:gpt-5

---------

Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-08-16 11:57:31 +02:00

59 lines
2.6 KiB
JavaScript

import { test, expect } from './coverage-fixtures.js'
test.describe('Navigation', () => {
test('/ redirects to /app', async ({ page }) => {
await page.goto('/')
await expect(page).toHaveURL(/\/app/)
})
test('/app shows the home page', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar')).toBeVisible()
await expect(page.locator('.home-page')).toBeVisible()
})
test('top menu exposes Home and Models', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar-nav a.nav-item[href="/app"]')).toBeVisible()
const models = page.locator('.sidebar-nav a.nav-item[href="/app/models"]')
await expect(models).toBeVisible()
await expect(models.locator('.nav-label')).toHaveText('Models')
})
test('Create stays an inline tier with Chat, Studio and Talk', async ({ page }) => {
await page.goto('/app')
await expect(page.locator('.sidebar-section-title', { hasText: 'Create' })).toBeVisible()
await expect(page.locator('.sidebar-nav a.nav-item[href="/app/chat"]')).toBeVisible()
await expect(page.locator('.sidebar-nav a.nav-item[href="/app/studio"]')).toBeVisible()
await expect(page.locator('.sidebar-nav a.nav-item[href="/app/talk"]')).toBeVisible()
})
test('Build is a single entry that opens the Build console', async ({ page }) => {
await page.goto('/app')
const build = page.locator('.sidebar-nav a.nav-item', { hasText: 'Build' })
await expect(build).toBeVisible()
await build.click()
await expect(page.locator('.console-rail .console-rail-header', { hasText: 'Build' })).toBeVisible()
})
test('Operate is a single entry that opens the admin console', async ({ page }) => {
await page.goto('/app')
const operate = page.locator('.sidebar-nav a.nav-item', { hasText: 'Operate' })
await expect(operate).toBeVisible()
await operate.click()
await expect(page.locator('.console-rail .console-rail-header', { hasText: 'Operate' })).toBeVisible()
})
test('Build console groups Automation, Training and Recognition', async ({ page }) => {
await page.goto('/app/agents')
const rail = page.locator('.console-rail')
await expect(rail).toBeVisible()
for (const group of ['Automation', 'Training', 'Recognition']) {
await expect(rail.locator('.console-group-title', { hasText: group })).toBeVisible()
}
// Recognition (Faces/Voices) and Training (Fine-tune/Quantize) live here now.
await expect(rail.locator('a.nav-item[href="/app/fine-tune"]')).toBeVisible()
await expect(rail.locator('a.nav-item[href="/app/face"]')).toBeVisible()
})
})