diff --git a/packages/backend/src/database/schema.ts b/packages/backend/src/database/schema.ts index aeeda7b..3ca3925 100644 --- a/packages/backend/src/database/schema.ts +++ b/packages/backend/src/database/schema.ts @@ -190,7 +190,6 @@ CREATE TABLE IF NOT EXISTS quick_command_tag_associations ( ); `; -// --- End Quick Command Tags --- // 从 database.ts 移动过来的,保持一致性 diff --git a/packages/backend/src/notifications/notification.controller.ts b/packages/backend/src/notifications/notification.controller.ts index f6e9e50..11a3d19 100644 --- a/packages/backend/src/notifications/notification.controller.ts +++ b/packages/backend/src/notifications/notification.controller.ts @@ -216,4 +216,4 @@ export class NotificationController { res.status(500).json({ message: i18next.t('notificationController.errorTriggerTest'), error: error.message }); } }; -} // End of class NotificationController +} diff --git a/packages/frontend/src/App.vue b/packages/frontend/src/App.vue index cf44947..1a6364f 100644 --- a/packages/frontend/src/App.vue +++ b/packages/frontend/src/App.vue @@ -271,6 +271,7 @@ const isElementVisibleAndFocusable = (element: HTMLElement): boolean => { Project Logo {{ t('nav.dashboard') }} {{ t('nav.terminal') }} + @@ -297,7 +298,7 @@ const isElementVisibleAndFocusable = (element: HTMLElement): boolean => {
- + diff --git a/packages/frontend/src/components/BatchEditConnectionForm.vue b/packages/frontend/src/components/BatchEditConnectionForm.vue new file mode 100644 index 0000000..f6d5b98 --- /dev/null +++ b/packages/frontend/src/components/BatchEditConnectionForm.vue @@ -0,0 +1,336 @@ + + + \ No newline at end of file diff --git a/packages/frontend/src/components/WorkspaceConnectionList.vue b/packages/frontend/src/components/WorkspaceConnectionList.vue index b0d8ded..fb221e2 100644 --- a/packages/frontend/src/components/WorkspaceConnectionList.vue +++ b/packages/frontend/src/components/WorkspaceConnectionList.vue @@ -972,18 +972,11 @@ const cancelEditingTag = () => { @click="handleTagMenuAction('deleteAllConnections')" > - {{ t('workspaceConnectionList.deleteAllConnectionsInGroupMenu') }} + {{ t('workspaceConnectionList.deleteAllConnectionsInGroupMenu') }} - - - { - diff --git a/packages/frontend/src/composables/useWebSocketConnection.ts b/packages/frontend/src/composables/useWebSocketConnection.ts index 291ed28..3eb3706 100644 --- a/packages/frontend/src/composables/useWebSocketConnection.ts +++ b/packages/frontend/src/composables/useWebSocketConnection.ts @@ -39,7 +39,7 @@ export function createWebSocketConnectionManager( let reconnectTimeoutId: ReturnType | null = null; // 重连定时器 ID let lastUrl = ''; // 保存上次连接的 URL let intentionalDisconnect = false; // 标记是否为用户主动断开 - // --- End Instance State --- + /** * 安全地获取状态文本的辅助函数 diff --git a/packages/frontend/src/features/appearance/config/default-themes.ts b/packages/frontend/src/features/appearance/config/default-themes.ts index 9730c79..d3b676e 100644 --- a/packages/frontend/src/features/appearance/config/default-themes.ts +++ b/packages/frontend/src/features/appearance/config/default-themes.ts @@ -42,7 +42,6 @@ export const defaultUiTheme: Record = { '--button-bg-color': '#A06CD5', // 现代紫色 - 激活 (基础) '--button-text-color': '#ffffff', '--button-hover-bg-color': '#8E44AD', // 现代紫色 - 悬停 (稍暗) - // Added new variables '--icon-color': 'var(--text-color-secondary)', // 图标颜色 '--icon-hover-color': 'var(--link-hover-color)', // 图标悬停颜色 (自动更新) '--split-line-color': 'var(--border-color)', /* 分割线颜色 */ @@ -50,7 +49,6 @@ export const defaultUiTheme: Record = { '--input-focus-border-color': 'var(--link-active-color)', /* 输入框聚焦边框颜色 (自动更新) */ '--input-focus-glow': 'var(--link-active-color)', /* 输入框聚焦光晕值 (自动更新) */ '--overlay-bg-color': 'rgba(0, 0, 0, 0.6)', /* Added Overlay Background - 恢复 rgba 以支持透明度 */ - // End added variables '--font-family-sans-serif': 'sans-serif', '--base-padding': '1rem', '--base-margin': '0.5rem', diff --git a/packages/frontend/src/locales/en-US.json b/packages/frontend/src/locales/en-US.json index 65d3501..4fb68cd 100644 --- a/packages/frontend/src/locales/en-US.json +++ b/packages/frontend/src/locales/en-US.json @@ -6,6 +6,7 @@ "nav": { "dashboard": "Dashboard", "terminal": "Terminal", + "connections": "Connections", "proxies": "Proxies", "login": "Login", "logout": "Logout", @@ -126,7 +127,18 @@ "lastConnected": "Last Connected", "actions": "Actions" }, + "batchEdit":{ + "toggleLabel":"Batch Edit", + "selectAll": "Select All", + "deselectAll": "Deselect All", + "invertSelection": "Invert Selection", + "title": "Batch Edit Connections", + "editSelected": "Edit Selected", + "noChange":"No change", + "selectedItems":"{count} items selected" + }, "actions": { + "testAllFiltered":"Test All", "connect": "Connect", "edit": "Edit", "delete": "Delete", @@ -151,6 +163,7 @@ "confirm": "Confirm Add", "adding": "Adding...", "cancel": "Cancel", + "noSshKey":"No SSH Key", "errorRequiredFields": "Please fill in all required fields.", "errorPasswordRequired": "Password is required for password authentication.", "errorPrivateKeyRequired": "Private key is required for key authentication.", @@ -968,6 +981,7 @@ "restore": "Restore", "minimize": "Minimize", "send":"Send", + "updateSuccess":"Update successful", "copied": "Copied to clipboard" }, "layoutConfigurator": { diff --git a/packages/frontend/src/locales/ja-JP.json b/packages/frontend/src/locales/ja-JP.json index e66455b..c9976d2 100644 --- a/packages/frontend/src/locales/ja-JP.json +++ b/packages/frontend/src/locales/ja-JP.json @@ -106,10 +106,22 @@ "restore": "元に戻す", "minimize": "最小化", "send":"送信する", + "updateSuccess":"更新に成功しました", "copied": "クリップボードにコピーしました" }, "connections": { + "batchEdit": { + "toggleLabel": "一括編集", + "selectAll": "すべて選択", + "deselectAll": "すべて選択解除", + "invertSelection": "選択を反転", + "title": "接続の一括編集", + "editSelected": "選択した項目を編集", + "noChange": "変更なし", + "selectedItems": "{count} 件選択済み" + }, "actions": { + "testAllFiltered":"すべてテスト", "connect": "接続", "delete": "削除", "edit": "編集", @@ -150,6 +162,7 @@ "password": "パスワード:", "port": "ポート:", "privateKey": "秘密鍵:", + "noSshKey":"SSHキーなし", "proxy": "プロキシ:", "saving": "保存中...", "sectionAdvanced": "詳細設定", @@ -575,6 +588,7 @@ "auditLogs": "監査ログ", "customizeStyle": "外観のカスタマイズ", "dashboard": "ダッシュボード", + "connections": "接続管理", "login": "ログイン", "logout": "ログアウト", "notifications": "通知管理", diff --git a/packages/frontend/src/locales/zh-CN.json b/packages/frontend/src/locales/zh-CN.json index 8f925e9..0dfbc42 100644 --- a/packages/frontend/src/locales/zh-CN.json +++ b/packages/frontend/src/locales/zh-CN.json @@ -6,6 +6,7 @@ "nav": { "dashboard": "仪表盘", "terminal": "终端", + "connections": "连接管理", "proxies": "代理管理", "login": "登录", "logout": "登出", @@ -125,7 +126,19 @@ "lastConnected": "上次连接", "actions": "操作" }, + "batchEdit":{ + "toggleLabel":"批量修改", + "selectAll": "全选", + "deselectAll": "取消全选", + "invertSelection": "反向选择", + "editSelected": "编辑所选", + "title": "批量编辑连接", + "selectedItems": "已选项目", + "noChange": "保持不变", + "tagsPlaceholder": "输入标签 (替换现有)" + }, "actions": { + "testAllFiltered":"测试全部", "connect": "连接", "edit": "编辑", "delete": "删除", @@ -180,6 +193,7 @@ "testConnection": "测试连接", "testing": "测试中...", "sshKey": "SSH 密钥", + "noSshKey":"无 SSH 密钥", "privateKeyDirect": "私钥内容", "keyUpdateNoteDirect": "编辑时将私钥和密码短语留空以保留现有密钥。", "keyUpdateNoteSelected": "编辑时选择其他密钥或使用直接输入来更改密钥。", @@ -969,7 +983,8 @@ "restore": "还原", "minimize": "最小化", "send":"发送", - "copied": "已复制到剪贴板" + "copied": "已复制到剪贴板", + "updateSuccess":"更新成功" }, "layoutConfigurator": { "title": "布局管理器", diff --git a/packages/frontend/src/router/index.ts b/packages/frontend/src/router/index.ts index a68c7e7..cff6037 100644 --- a/packages/frontend/src/router/index.ts +++ b/packages/frontend/src/router/index.ts @@ -22,6 +22,12 @@ const routes: Array = [ name: 'Proxies', component: () => import('../views/ProxiesView.vue') }, + // 连接管理页面 + { + path: '/connections', + name: 'Connections', + component: () => import('../views/ConnectionsView.vue') + }, // 移除:标签管理页面路由 // { // path: '/tags', diff --git a/packages/frontend/src/stores/connections.store.ts b/packages/frontend/src/stores/connections.store.ts index 0cde114..28f5d6d 100644 --- a/packages/frontend/src/stores/connections.store.ts +++ b/packages/frontend/src/stores/connections.store.ts @@ -191,13 +191,14 @@ export const useConnectionsStore = defineStore('connections', { }, // 测试连接 Action - async testConnection(connectionId: number): Promise<{ success: boolean; message?: string }> { + async testConnection(connectionId: number): Promise<{ success: boolean; message?: string; latency?: number }> { // 注意:这里不改变 isLoading 状态,或者可以引入单独的 testing 状态 // this.isLoading = true; // this.error = null; try { - const response = await apiClient.post<{ success: boolean; message: string }>(`/connections/${connectionId}/test`); // 使用 apiClient - return { success: response.data.success, message: response.data.message }; + // 假设后端返回 { success: boolean; message: string; latency?: number } + const response = await apiClient.post<{ success: boolean; message: string; latency?: number }>(`/connections/${connectionId}/test`); // 使用 apiClient + return { success: response.data.success, message: response.data.message, latency: response.data.latency }; } catch (err: any) { console.error(`测试连接 ${connectionId} 失败:`, err); const errorMessage = err.response?.data?.message || err.message || '测试连接时发生未知错误。'; diff --git a/packages/frontend/src/stores/fileEditor.store.ts b/packages/frontend/src/stores/fileEditor.store.ts index b7d912f..be03293 100644 --- a/packages/frontend/src/stores/fileEditor.store.ts +++ b/packages/frontend/src/stores/fileEditor.store.ts @@ -96,7 +96,7 @@ const decodeRawContent = (rawContentBase64: string, encoding: string): string => return `// Error decoding content: ${error.message}`; // 返回错误信息 } }; -// --- End Helper Functions --- + export const useFileEditorStore = defineStore('fileEditor', () => { const { t } = useI18n(); diff --git a/packages/frontend/src/stores/quickCommands.store.ts b/packages/frontend/src/stores/quickCommands.store.ts index e755888..9ed2e54 100644 --- a/packages/frontend/src/stores/quickCommands.store.ts +++ b/packages/frontend/src/stores/quickCommands.store.ts @@ -462,7 +462,6 @@ export const useQuickCommandsStore = defineStore('quickCommands', () => { } }); console.log(`[Store] Manually updated tagIds for ${updatedCount} commands in local state.`); - // --- End manual state update --- // Optionally, still fetch for full consistency, but UI should update based on manual change first. // clearQuickCommandsCache(); diff --git a/packages/frontend/src/views/ConnectionsView.vue b/packages/frontend/src/views/ConnectionsView.vue new file mode 100644 index 0000000..45bb5ca --- /dev/null +++ b/packages/frontend/src/views/ConnectionsView.vue @@ -0,0 +1,698 @@ + + + \ No newline at end of file diff --git a/packages/frontend/src/views/DashboardView.vue b/packages/frontend/src/views/DashboardView.vue index e0df043..dc83446 100644 --- a/packages/frontend/src/views/DashboardView.vue +++ b/packages/frontend/src/views/DashboardView.vue @@ -355,7 +355,7 @@ const handleConnectionModified = async () => {
- {{ conn.name || t('connections.unnamed') }} + {{ conn.name || conn.host || t('connections.unnamedFallback', '未命名连接') }} {{ conn.username }}@{{ conn.host }}:{{ conn.port }} diff --git a/packages/frontend/src/views/LoginView.vue b/packages/frontend/src/views/LoginView.vue index 919ba32..845e817 100644 --- a/packages/frontend/src/views/LoginView.vue +++ b/packages/frontend/src/views/LoginView.vue @@ -51,7 +51,6 @@ const resetCaptchaWidget = () => { // Reset reCAPTCHA v2 if it exists recaptchaWidget.value?.reset(); }; -// --- End CAPTCHA Event Handlers --- // 处理登录或 2FA 验证提交 @@ -67,8 +66,6 @@ const handleSubmit = async () => { return; // Stop submission if CAPTCHA is required but not completed } } - // --- End CAPTCHA Check --- - // --- End CAPTCHA Check --- try { if (loginRequires2FA.value) {