feat(ui): move settings under the operate hub

The Operate hub already has Settings as a tab, so the sidebar no longer shows a separate Settings entry. The /app/settings route stays, and the hub tab still reaches it. The navigation test now expects Chat, Models and Add-ons as the primary items.

Assisted-by: Claude Code:claude-sonnet-5-5 node
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto committed 2026-10-20 20:54:44 +00:00
1 parent 6e34303348
commit e5710a5af0
4 files changed
+9 -9

No files matched your search

@@ -18,8 +18,8 @@ import Icon from './Icon'
const COLLAPSED_KEY = 'localai_sidebar_collapsed'
const SECTIONS_KEY = 'localai_sidebar_sections'
// The sidebar has two layouts. The four-item layout shows Home, Chat, Models,
// Add-ons and Settings, the Pinned section, and Build and Operate under
// The sidebar has two layouts. The four-item layout shows Home, Chat, Models
// and Add-ons, the Pinned section, and Build and Operate under
// Workspace. With the legacy switch on (features.addon_navigation === false)
// it shows Home and Models, the Create group (Chat, Studio, Talk) and
// Workspace. Build and Operate are single entries; each opens a hub whose tab
+1 -1
View File
@@ -36,7 +36,7 @@ export function destinationsFor(auth) {
]
}
// The four-item layout: Home, then Chat, Models, Add-ons and Settings, then the hubs.
// The four-item layout: Home, then Chat, Models and Add-ons, then the hubs.
export function destinationsForNavigation(auth) {
const hubItems = hubs.flatMap(hub => {
const path = hubEntryPath(hub, auth)
+3 -3
View File
@@ -1,14 +1,14 @@
// Pure rules of the four-item sidebar. No React, no imports, so a node test
// drives it directly.
// Chat, Models, Add-ons and Settings. Home and the Build and Operate hubs keep
// the place they have today (see hubConfig.js and destinations.js).
// Chat, Models and Add-ons. Home and the Build and Operate hubs keep the place
// they have today (see hubConfig.js and destinations.js). Settings is a tab of
// the Operate hub, not a primary item.
export const primaryDestinations = Object.freeze([
{ path: '/app/chat', icon: 'chat', labelKey: 'items.chat' },
{ path: '/app/models', icon: 'boxes', labelKey: 'items.models', adminOnly: true },
// Shown to a viewer who holds the addons feature or sees a built-in tile.
{ path: '/app/addons', icon: 'puzzle', labelKey: 'items.addons', addonsEntry: true },
{ path: '/app/settings', icon: 'settings', labelKey: 'items.settings', adminOnly: true },
])
export function visiblePrimary(items, { isAdmin, hasFeature, hasBuiltin }) {
@@ -79,10 +79,10 @@ test('movePin moves one place and stops at the ends', () => {
const user = { isAdmin: false, authEnabled: true, hasFeature: () => false, features: {}, hasBuiltin: false }
test('the sidebar has four primary items and Settings and Models are administrator items', () => {
assert.deepEqual(primaryDestinations.map(i => i.path), ['/app/chat', '/app/models', '/app/addons', '/app/settings'])
test('Settings is not a primary item and Models is an administrator item', () => {
assert.deepEqual(primaryDestinations.map(i => i.path), ['/app/chat', '/app/models', '/app/addons'])
const admin = visiblePrimary(primaryDestinations, { ...user, isAdmin: true, hasFeature: () => true })
assert.equal(admin.length, 4)
assert.equal(admin.length, 3)
const member = visiblePrimary(primaryDestinations, { ...user, hasBuiltin: true })
assert.deepEqual(member.map(i => i.path), ['/app/chat', '/app/addons'])
})