feat: expose remote control as admin module

This commit is contained in:
elky
2026-09-06 00:13:57 +08:00
parent c125e78c5f
commit dba5e6e9e9
6 changed files with 82 additions and 19 deletions
+6 -6
View File
@@ -275,8 +275,8 @@ export const messages = {
'nav.healthMonitor': '健康监控',
'nav.modelCatalog': '模型目录',
'nav.apiKeys': 'API 密钥',
'nav.vscodex': 'Codex 远程控制',
'vscodex.title': 'Codex 远程控制',
'nav.vscodex': '远程控制',
'vscodex.title': '远程控制',
'vscodex.devices.label': '控制设备',
'vscodex.devices.refresh': '刷新设备',
'vscodex.devices.loading': '正在加载设备...',
@@ -305,7 +305,7 @@ export const messages = {
'vscodex.connection.connecting': '正在建立安全连接...',
'vscodex.connection.ticketFailed': '安全连接凭证获取失败。',
'vscodex.connection.retry': '重试',
'vscodex.frame.title': 'Codex 远程控制台',
'vscodex.frame.title': '远程控制台',
'nav.walletCenter': '钱包中心',
'nav.billingCenter': '套餐中心',
'nav.myReferral': '我的邀请',
@@ -692,8 +692,8 @@ export const messages = {
'nav.healthMonitor': 'Health monitor',
'nav.modelCatalog': 'Model catalog',
'nav.apiKeys': 'API keys',
'nav.vscodex': 'Codex remote control',
'vscodex.title': 'Codex remote control',
'nav.vscodex': 'Remote control',
'vscodex.title': 'Remote control',
'vscodex.devices.label': 'Control device',
'vscodex.devices.refresh': 'Refresh devices',
'vscodex.devices.loading': 'Loading devices...',
@@ -722,7 +722,7 @@ export const messages = {
'vscodex.connection.connecting': 'Establishing a secure connection...',
'vscodex.connection.ticketFailed': 'A secure connection ticket could not be issued.',
'vscodex.connection.retry': 'Retry',
'vscodex.frame.title': 'Codex remote control surface',
'vscodex.frame.title': 'Remote control surface',
'nav.walletCenter': 'Wallet',
'nav.billingCenter': 'Plans',
'nav.myReferral': 'Referrals',
@@ -37,19 +37,27 @@ describe('main layout navigation builder', () => {
expect(navigation.flatMap(group => group.items.map(item => item.name))).toContain('tx:nav.myReferral')
})
it('exposes the same VS Code control destination to users and administrators', () => {
const commonOptions = {
it('exposes remote control to users and active administrators', () => {
const userNavigation = buildNavigation({
canAccessAdmin: false,
modules: {},
isModuleActive: () => false,
t: translate,
}
const userNavigation = buildNavigation({
...commonOptions,
canAccessAdmin: false,
})
const adminNavigation = buildNavigation({
...commonOptions,
canAccessAdmin: true,
modules: {
vscodex: {
active: true,
admin_route: '/dashboard/vscodex',
admin_menu_group: 'overview',
admin_menu_order: 80,
admin_menu_icon: 'SquareTerminal',
display_name: '远程控制',
},
},
isModuleActive: () => false,
t: translate,
})
const findVscodeControl = (navigation: ReturnType<typeof buildNavigation>) => (
@@ -63,9 +71,14 @@ describe('main layout navigation builder', () => {
href: '/dashboard/vscodex',
})
expect(findVscodeControl(adminNavigation)).toMatchObject({
name: 'tx:nav.vscodex',
name: '远程控制',
href: '/dashboard/vscodex',
})
const overviewItems = adminNavigation.find(group => group.title === 'tx:nav.group.overview')?.items ?? []
expect(overviewItems.findIndex(item => item.name === '远程控制')).toBe(
overviewItems.findIndex(item => item.name === 'tx:nav.performanceAnalysis') + 1,
)
})
it('builds admin navigation with dynamic module menu items sorted by menu order', () => {
@@ -133,13 +146,36 @@ describe('main layout navigation builder', () => {
expect(buildBreadcrumbs({
route: route('/dashboard/vscodex'),
navigation,
modules: {},
navigation: buildNavigation({
canAccessAdmin: true,
modules: {
vscodex: {
active: true,
admin_route: '/dashboard/vscodex',
admin_menu_group: 'overview',
admin_menu_order: 80,
admin_menu_icon: 'SquareTerminal',
display_name: '远程控制',
},
},
isModuleActive: () => false,
t: translate,
}),
modules: {
vscodex: {
active: true,
admin_route: '/dashboard/vscodex',
admin_menu_group: 'overview',
admin_menu_order: 80,
admin_menu_icon: 'SquareTerminal',
display_name: '远程控制',
},
},
isNavActive: href => href === '/dashboard/vscodex',
t: translate,
})).toEqual([
expect.objectContaining({ label: expect.any(String) }),
{ label: 'tx:nav.vscodex' },
{ label: '远程控制' },
])
})
})
@@ -51,6 +51,7 @@ const moduleIconMap: Record<string, LucideIcon> = {
Server,
Send,
SlidersHorizontal,
SquareTerminal,
CreditCard,
Gift,
}
@@ -117,12 +118,12 @@ export function buildNavigation(options: {
title: t('nav.group.overview'),
items: [
{ name: t('nav.dashboard'), href: '/admin/dashboard', icon: Home },
{ name: t('nav.vscodex'), href: '/dashboard/vscodex', icon: SquareTerminal },
{ name: t('nav.operations'), href: '/admin/operations', icon: Activity },
{ name: t('nav.healthMonitor'), href: '/admin/health-monitor', icon: Activity },
{ name: t('nav.userStats'), href: '/admin/user-stats', icon: BarChart3 },
{ name: t('nav.costAnalysis'), href: '/admin/cost-analysis', icon: Gauge },
{ name: t('nav.performanceAnalysis'), href: '/admin/performance-analysis', icon: Activity },
...activeModuleItems(modules, 'overview'),
]
},
{
+14
View File
@@ -1138,6 +1138,20 @@ const MOCK_MODULE_DEFINITIONS: Array<Omit<ModuleStatus, 'active' | 'health'> & {
admin_menu_group: null,
admin_menu_order: 59,
},
{
name: 'vscodex',
display_name: '远程控制',
description: '通过 aether-vscodex 插件远程控制本地 Codex 工作区',
category: 'integration',
available: true,
enabled: false,
config_validated: true,
config_error: null,
admin_route: '/dashboard/vscodex',
admin_menu_icon: 'SquareTerminal',
admin_menu_group: 'overview',
admin_menu_order: 80,
},
{
name: 's3_backup',
display_name: 'S3 备份',