From e5710a5af0df35b3ff638fa29b8993c2dc450871 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Tue, 20 Oct 2026 12:11:44 +0000 Subject: [PATCH] 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 --- core/http/react-ui/src/components/Sidebar.jsx | 4 ++-- core/http/react-ui/src/utils/destinations.js | 2 +- core/http/react-ui/src/utils/navigationModel.js | 6 +++--- core/http/react-ui/tests/unit/navigation.test.mjs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/http/react-ui/src/components/Sidebar.jsx b/core/http/react-ui/src/components/Sidebar.jsx index 0aff142c3..a4aa9499b 100644 --- a/core/http/react-ui/src/components/Sidebar.jsx +++ b/core/http/react-ui/src/components/Sidebar.jsx @@ -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 diff --git a/core/http/react-ui/src/utils/destinations.js b/core/http/react-ui/src/utils/destinations.js index 65373a369..b6e81c5ba 100644 --- a/core/http/react-ui/src/utils/destinations.js +++ b/core/http/react-ui/src/utils/destinations.js @@ -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) diff --git a/core/http/react-ui/src/utils/navigationModel.js b/core/http/react-ui/src/utils/navigationModel.js index e690ae4d5..b3844f7e9 100644 --- a/core/http/react-ui/src/utils/navigationModel.js +++ b/core/http/react-ui/src/utils/navigationModel.js @@ -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 }) { diff --git a/core/http/react-ui/tests/unit/navigation.test.mjs b/core/http/react-ui/tests/unit/navigation.test.mjs index ea2cbae2c..b832983de 100644 --- a/core/http/react-ui/tests/unit/navigation.test.mjs +++ b/core/http/react-ui/tests/unit/navigation.test.mjs @@ -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']) })