diff --git a/.downstream/native-domains.md b/.downstream/native-domains.md index 95ad9c42a480..50ec349c4738 100644 --- a/.downstream/native-domains.md +++ b/.downstream/native-domains.md @@ -19,7 +19,8 @@ nothing. While no Codex runtime row is stored, ## Codex gateway borrowing -The Extensions navigation exposes three administrator pages: settings at +The Extensions sidebar has one Codex Borrowing entry. Its in-page navigation +switches between three independently addressable administrator pages: settings at `/admin/codex-gateway-borrow`, route status at `/admin/codex-gateway-borrow/status`, and manual comparison/history at `/admin/codex-pelican-comparison`. Opening or navigating these pages only reads diff --git a/frontend/src/components/layout/AppSidebar.vue b/frontend/src/components/layout/AppSidebar.vue index c650b5e59845..67f86aea5eed 100644 --- a/frontend/src/components/layout/AppSidebar.vue +++ b/frontend/src/components/layout/AppSidebar.vue @@ -113,7 +113,7 @@ :key="item.path" :to="item.path" class="sidebar-link mb-1" - :class="{ 'sidebar-link-active': route.path === item.path, 'sidebar-link-collapsed': sidebarCollapsed }" + :class="{ 'sidebar-link-active': isExtensionActive(item.path), 'sidebar-link-collapsed': sidebarCollapsed }" :title="sidebarCollapsed ? item.label : undefined" @click="handleMenuItemClick(item.path)" > @@ -507,14 +507,6 @@ const GatewayBorrowIcon = { render: () => h(Icon, { name: 'link', 'aria-hidden': 'true' }) } -const GatewayBorrowStatusIcon = { - render: () => h(Icon, { name: 'checkCircle', 'aria-hidden': 'true' }) -} - -const PelicanComparisonIcon = { - render: () => h(Icon, { name: 'grid', 'aria-hidden': 'true' }) -} - const BellIcon = { render: () => h( @@ -842,8 +834,6 @@ const adminExtensionNavItems = computed((): NavItem[] => [ { path: '/admin/system-prompts', label: t('nav.systemPrompts'), icon: DocumentIcon }, { path: '/admin/codex-runtime', label: t('nav.codexRuntime'), icon: PluginIcon }, { path: '/admin/codex-gateway-borrow', label: t('nav.codexGatewayBorrow'), icon: GatewayBorrowIcon }, - { path: '/admin/codex-gateway-borrow/status', label: t('nav.codexGatewayBorrowStatus'), icon: GatewayBorrowStatusIcon }, - { path: '/admin/codex-pelican-comparison', label: t('nav.codexPelicanComparison'), icon: PelicanComparisonIcon }, { path: '/admin/reasoning-recovery', label: t('nav.reasoningRecovery'), icon: RecoveryIcon }, ]) @@ -986,6 +976,13 @@ function isActive(path: string): boolean { return route.path === path || route.path.startsWith(path + '/') } +function isExtensionActive(path: string): boolean { + if (path === '/admin/codex-gateway-borrow') { + return isActive(path) || route.path === '/admin/codex-pelican-comparison' + } + return route.path === path +} + function isGroupActive(item: NavItem): boolean { if (!item.children) return false return item.children.some(child => route.path === child.path) diff --git a/frontend/src/components/layout/__tests__/AppSidebar.simple-mode.spec.ts b/frontend/src/components/layout/__tests__/AppSidebar.simple-mode.spec.ts index 127b4764c7c7..7a6375022e3d 100644 --- a/frontend/src/components/layout/__tests__/AppSidebar.simple-mode.spec.ts +++ b/frontend/src/components/layout/__tests__/AppSidebar.simple-mode.spec.ts @@ -105,15 +105,13 @@ describe('AppSidebar simple mode extensions', () => { wrapper.unmount() }) - it.each([true, false])('renders the three admin page entries in order (simple: %s)', async simple => { + it.each([true, false])('renders one borrowing entry with page navigation kept inside (simple: %s)', async simple => { const wrapper = await renderSidebar({ admin: true, simple }) expect(extensionLinks(wrapper)).toEqual([ '/admin/system-prompts', '/admin/codex-runtime', '/admin/codex-gateway-borrow', - '/admin/codex-gateway-borrow/status', - '/admin/codex-pelican-comparison', '/admin/reasoning-recovery', ]) if (simple) expect(wrapper.text()).not.toContain('nav.myAccount') @@ -126,12 +124,17 @@ describe('AppSidebar simple mode extensions', () => { regularUser.unmount() }) - it('marks only Borrow Status active on its own route', async () => { - const wrapper = await renderSidebar({ admin: true, path: '/admin/codex-gateway-borrow/status' }) + it.each([ + '/admin/codex-gateway-borrow', + '/admin/codex-gateway-borrow/status', + '/admin/codex-pelican-comparison', + ])('keeps the single borrowing entry active on %s', async path => { + const wrapper = await renderSidebar({ admin: true, path }) const section = wrapper.get('[data-testid="sidebar-extensions"]') - expect(section.get('a[href="/admin/codex-gateway-borrow/status"]').classes()).toContain('sidebar-link-active') - expect(section.get('a[href="/admin/codex-gateway-borrow"]').classes()).not.toContain('sidebar-link-active') + expect(section.get('a[href="/admin/codex-gateway-borrow"]').classes()).toContain('sidebar-link-active') + expect(section.find('a[href="/admin/codex-gateway-borrow/status"]').exists()).toBe(false) + expect(section.find('a[href="/admin/codex-pelican-comparison"]').exists()).toBe(false) expect(section.findAll('.sidebar-link-active')).toHaveLength(1) wrapper.unmount() }) diff --git a/frontend/src/i18n/locales/en/common.ts b/frontend/src/i18n/locales/en/common.ts index a9afc27e57f8..d4150ccd2063 100644 --- a/frontend/src/i18n/locales/en/common.ts +++ b/frontend/src/i18n/locales/en/common.ts @@ -223,7 +223,7 @@ export default { auditLogs: 'Audit Logs', systemPrompts: 'System Prompts', reasoningRecovery: 'Reasoning Recovery', - codexGatewayBorrow: 'Codex Borrow Settings', + codexGatewayBorrow: 'Codex Borrowing', codexGatewayBorrowStatus: 'Codex Borrow Status', codexPelicanComparison: 'Pelican Comparison', }, diff --git a/frontend/src/i18n/locales/zh/common.ts b/frontend/src/i18n/locales/zh/common.ts index bf000300ec98..74e4cdbe3503 100644 --- a/frontend/src/i18n/locales/zh/common.ts +++ b/frontend/src/i18n/locales/zh/common.ts @@ -223,7 +223,7 @@ export default { auditLogs: '操作日志', systemPrompts: '系统提示词', reasoningRecovery: '推理恢复', - codexGatewayBorrow: 'Codex 借用设置', + codexGatewayBorrow: 'Codex 借用', codexGatewayBorrowStatus: 'Codex 借用状态', codexPelicanComparison: '鹈鹕对比', }, diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index edbedae45971..06c758ff9c71 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -547,7 +547,7 @@ const routes: RouteRecordRaw[] = [ path: '/admin/codex-gateway-borrow', name: 'AdminCodexGatewayBorrow', component: () => import('@/views/admin/CodexGatewayBorrowView.vue'), - meta: { requiresAuth: true, requiresAdmin: true, title: 'Codex Borrow Settings', titleKey: 'nav.codexGatewayBorrow' } + meta: { requiresAuth: true, requiresAdmin: true, title: 'Codex Borrow Settings', titleKey: 'admin.codexGatewayBorrow.title' } }, { path: '/admin/codex-gateway-borrow/status',