diff --git a/packages/frontend/src/locales/en-US.json b/packages/frontend/src/locales/en-US.json
index 007d0e9..c1e9e71 100644
--- a/packages/frontend/src/locales/en-US.json
+++ b/packages/frontend/src/locales/en-US.json
@@ -1006,7 +1006,14 @@
"empty": "No history records",
"confirmClear": "Are you sure you want to clear all history?",
"copied": "Copied to clipboard",
- "copyFailed": "Copy failed"
+ "copyFailed": "Copy failed",
+ "actions": {
+ "sendToAllSessions": "Send to All Sessions"
+ },
+ "notifications": {
+ "sentToAllSessions": "Command sent to {count} sessions.",
+ "noActiveSshSessions": "No active SSH sessions to send command to."
+ }
},
"quickCommands": {
"searchPlaceholder": "Search name or command...",
@@ -1032,6 +1039,13 @@
"untagged": "Untagged",
"tags": {
"clickToEditTag": "Click to edit tag name"
+ },
+ "actions": {
+ "sendToAllSessions": "Send to All Sessions"
+ },
+ "notifications": {
+ "sentToAllSessions": "Command sent to {count} sessions.",
+ "noActiveSshSessions": "No active SSH sessions to send command to."
}
},
"setup": {
diff --git a/packages/frontend/src/locales/ja-JP.json b/packages/frontend/src/locales/ja-JP.json
index 5a47852..e34c2f9 100644
--- a/packages/frontend/src/locales/ja-JP.json
+++ b/packages/frontend/src/locales/ja-JP.json
@@ -57,9 +57,16 @@
"delete": "削除",
"empty": "履歴はありません",
"loading": "ロード中...",
- "searchPlaceholder": "履歴を検索..."
- },
- "commandInputBar": {
+ "searchPlaceholder": "履歴を検索...",
+ "actions": {
+ "sendToAllSessions": "すべてのセッションに送信"
+ },
+ "notifications": {
+ "sentToAllSessions": "コマンドは {count} 個のセッションに送信されました。",
+ "noActiveSshSessions": "コマンドを送信するアクティブな SSH セッションはありません。"
+ }
+ },
+ "commandInputBar": {
"closeSearch": "ターミナル検索を閉じる",
"configureFocusSwitch": "フォーカススイッチャーを設定",
"findNext": "次を検索",
@@ -572,9 +579,16 @@
"searchPlaceholder": "名前またはコマンドを検索...",
"sortByName": "名前",
"sortByUsage": "使用頻度",
- "usageCount": "使用回数"
- },
- "remoteDesktopModal": {
+ "usageCount": "使用回数",
+ "actions": {
+ "sendToAllSessions": "すべてのセッションに送信"
+ },
+ "notifications": {
+ "sentToAllSessions": "コマンドは {count} 個のセッションに送信されました。",
+ "noActiveSshSessions": "コマンドを送信するアクティブな SSH セッションはありません。"
+ }
+ },
+ "remoteDesktopModal": {
"errors": {
"clientError": "クライアントエラー",
"connectionFailed": "接続に失敗しました",
diff --git a/packages/frontend/src/locales/zh-CN.json b/packages/frontend/src/locales/zh-CN.json
index e1a1b5a..366ff94 100644
--- a/packages/frontend/src/locales/zh-CN.json
+++ b/packages/frontend/src/locales/zh-CN.json
@@ -1008,7 +1008,14 @@
"empty": "没有历史记录",
"confirmClear": "确定要清空所有历史记录吗?",
"copied": "已复制到剪贴板",
- "copyFailed": "复制失败"
+ "copyFailed": "复制失败",
+ "actions": {
+ "sendToAllSessions": "发送到全部会话"
+ },
+ "notifications": {
+ "sentToAllSessions": "指令已发送到 {count} 个会话。",
+ "noActiveSshSessions": "没有活动的 SSH 会话可发送指令。"
+ }
},
"quickCommands": {
"searchPlaceholder": "搜索名称或指令...",
@@ -1034,6 +1041,13 @@
"untagged": "未标记",
"tags": {
"clickToEditTag": "点击编辑标签名称"
+ },
+ "actions": {
+ "sendToAllSessions": "发送到全部会话"
+ },
+ "notifications": {
+ "sentToAllSessions": "指令已发送到 {count} 个会话。",
+ "noActiveSshSessions": "没有活动的 SSH 会话可发送指令。"
}
},
"setup": {
diff --git a/packages/frontend/src/views/CommandHistoryView.vue b/packages/frontend/src/views/CommandHistoryView.vue
index 0a1d3f2..74005b0 100644
--- a/packages/frontend/src/views/CommandHistoryView.vue
+++ b/packages/frontend/src/views/CommandHistoryView.vue
@@ -40,6 +40,7 @@
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': index === storeSelectedIndex }"
@click="executeCommand(entry.command)"
+ @contextmenu.prevent="showCommandHistoryContextMenu($event, entry)"
:title="entry.command"
>
@@ -59,29 +60,57 @@
+
+
+
+
+ -
+ {{ t('commandHistory.actions.sendToAllSessions', '发送到全部会话') }}
+
+
+
diff --git a/packages/frontend/src/views/QuickCommandsView.vue b/packages/frontend/src/views/QuickCommandsView.vue
index 284fdee..372eca1 100644
--- a/packages/frontend/src/views/QuickCommandsView.vue
+++ b/packages/frontend/src/views/QuickCommandsView.vue
@@ -1,4 +1,4 @@
-
+
@@ -96,6 +96,7 @@
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': isCommandSelected(cmd.id) }"
@click="executeCommand(cmd)"
+ @contextmenu.prevent="showQuickCommandContextMenu($event, cmd)"
>
@@ -125,6 +126,7 @@
class="group flex justify-between items-center px-3 py-2.5 mb-1 cursor-pointer rounded-md hover:bg-primary/10 transition-colors duration-150"
:class="{ 'bg-primary/20 font-medium': isCommandSelected(cmd.id) }"
@click="executeCommand(cmd)"
+ @contextmenu.prevent="showQuickCommandContextMenu($event, cmd)"
>
@@ -153,33 +155,55 @@
:command-to-edit="commandToEdit"
@close="closeForm"
/>
+
+
+
+
+ -
+ {{ t('quickCommands.actions.sendToAllSessions', '发送到全部会话') }}
+
+
+
diff --git a/packages/frontend/src/views/WorkspaceView.vue b/packages/frontend/src/views/WorkspaceView.vue
index ae2afb3..c090162 100644
--- a/packages/frontend/src/views/WorkspaceView.vue
+++ b/packages/frontend/src/views/WorkspaceView.vue
@@ -120,7 +120,7 @@ onMounted(() => {
// 确保布局已初始化 (layoutStore 内部会处理)
// +++ 订阅工作区事件 +++
- subscribeToWorkspaceEvents('terminal:sendCommand', (payload) => handleSendCommand(payload.command));
+ subscribeToWorkspaceEvents('terminal:sendCommand', (payload) => handleSendCommand(payload.command, payload.sessionId));
subscribeToWorkspaceEvents('terminal:input', handleTerminalInput);
subscribeToWorkspaceEvents('terminal:resize', handleTerminalResize);
subscribeToWorkspaceEvents('terminal:ready', handleTerminalReady);
@@ -162,7 +162,7 @@ onBeforeUnmount(() => {
sessionStore.cleanupAllSessions();
// +++ 取消订阅工作区事件 +++
- unsubscribeFromWorkspaceEvents('terminal:sendCommand', (payload) => handleSendCommand(payload.command));
+ unsubscribeFromWorkspaceEvents('terminal:sendCommand', (payload) => handleSendCommand(payload.command, payload.sessionId));
unsubscribeFromWorkspaceEvents('terminal:input', handleTerminalInput);
unsubscribeFromWorkspaceEvents('terminal:resize', handleTerminalResize);
unsubscribeFromWorkspaceEvents('terminal:ready', handleTerminalReady);
@@ -237,42 +237,45 @@ const unsubscribeFromWorkspaceEvents = useWorkspaceEventOff();
// --- 事件处理 (传递给 LayoutRenderer 或直接使用) ---
// 处理命令发送 (用于 CommandBar, CommandHistory, QuickCommands)
- const handleSendCommand = (command: string) => {
- const currentSession = activeSession.value;
- if (!currentSession) {
- console.warn('[WorkspaceView] Cannot send command, no active session.');
+ const handleSendCommand = (command: string, targetSessionId?: string) => {
+ const sessionToCommand = targetSessionId ? sessionStore.sessions.get(targetSessionId) : activeSession.value;
+
+ if (!sessionToCommand) {
+ const idForLog = targetSessionId || 'active (none found)';
+ console.warn(`[WorkspaceView] Cannot send command, no session found for ID: ${idForLog}.`);
return;
}
- const terminalManager = currentSession.terminalManager as (SshTerminalInstance | undefined);
+ const terminalManager = sessionToCommand.terminalManager as (SshTerminalInstance | undefined);
if (terminalManager?.isSshConnected && !terminalManager.isSshConnected.value && command.trim() === '') {
- console.log(`[WorkspaceView] Command bar Enter detected in disconnected session ${currentSession.sessionId}, attempting reconnect...`);
+ console.log(`[WorkspaceView] Command bar Enter detected in disconnected session ${sessionToCommand.sessionId}, attempting reconnect...`);
if (terminalManager.terminalInstance?.value) {
terminalManager.terminalInstance.value.writeln(`\r\n\x1b[33m${t('workspace.terminal.reconnectingMsg')}\x1b[0m`);
}
- // +++ 修复:传递 ConnectionInfo 而不是 ID +++
- const connectionInfo = connectionsStore.connections.find(c => c.id === Number(currentSession.connectionId));
+ const connectionInfo = connectionsStore.connections.find(c => c.id === Number(sessionToCommand.connectionId));
if (connectionInfo) {
sessionStore.handleConnectRequest(connectionInfo);
} else {
- console.error(`[WorkspaceView] handleSendCommand: 未找到 ID 为 ${currentSession.connectionId} 的连接信息。`);
+ console.error(`[WorkspaceView] handleSendCommand: 未找到 ID 为 ${sessionToCommand.connectionId} 的连接信息。`);
}
return;
}
if (terminalManager && typeof terminalManager.sendData === 'function') {
- const commandToSend = command.trim();
- console.log(`[WorkspaceView] Sending command/data to active session ${currentSession.sessionId}: ${JSON.stringify(command)}`); // Log raw command
+ const commandToSend = command.trim(); // Keep trimmed for history
+ console.log(`[WorkspaceView] Sending command/data to session ${sessionToCommand.sessionId}: ${JSON.stringify(command)}`); // Log raw command
// Only append '\r' for regular commands, not for control characters like Ctrl+C (\x03)
+ // Send the raw command as received by the function for control characters
const dataToSend = command === '\x03' ? command : command + '\r';
terminalManager.sendData(dataToSend);
+
// Add to history only if it's a user-typed command (not just Enter or control chars)
- const commandToHistory = command.trim();
- if (commandToHistory.length > 0 && command !== '\x03') {
+ // And only if the command is being sent to the active session (to avoid polluting history from "send to all")
+ if (commandToSend.length > 0 && command !== '\x03' && sessionToCommand.sessionId === activeSessionId.value) {
commandHistoryStore.addCommand(commandToSend);
}
} else {
- console.warn(`[WorkspaceView] Cannot send command for session ${currentSession.sessionId}, terminal manager or sendData method not available.`);
+ console.warn(`[WorkspaceView] Cannot send command for session ${sessionToCommand.sessionId}, terminal manager or sendData method not available.`);
}
};