diff --git a/packages/frontend/src/components/WorkspaceConnectionList.vue b/packages/frontend/src/components/WorkspaceConnectionList.vue index 4db98cb..f4990d3 100644 --- a/packages/frontend/src/components/WorkspaceConnectionList.vue +++ b/packages/frontend/src/components/WorkspaceConnectionList.vue @@ -38,6 +38,11 @@ const contextMenuVisible = ref(false); const contextMenuPosition = ref({ x: 0, y: 0 }); const contextTargetConnection = ref(null); +// 标签右键菜单状态 +const tagContextMenuVisible = ref(false); +const tagContextMenuPosition = ref({ x: 0, y: 0 }); +const contextTargetTagGroup = ref<(typeof filteredAndGroupedConnections.value)[0] | null>(null); + // +++ 本地存储键名 +++ const EXPANDED_GROUPS_STORAGE_KEY = 'workspaceConnectionListExpandedGroups'; @@ -380,6 +385,50 @@ const handleMenuAction = (action: 'add' | 'edit' | 'delete' | 'clone') => { // } }; +// 显示标签右键菜单 +const showTagContextMenu = (event: MouseEvent, groupData: (typeof filteredAndGroupedConnections.value)[0]) => { + event.preventDefault(); + event.stopPropagation(); // 阻止事件冒泡到上层,例如关闭连接右键菜单的 document click listener + closeContextMenu(); // 如果连接的右键菜单是打开的,先关闭它 + contextTargetTagGroup.value = groupData; + tagContextMenuPosition.value = { x: event.clientX, y: event.clientY }; + tagContextMenuVisible.value = true; + // 添加全局点击监听器以关闭菜单 + document.addEventListener('click', closeTagContextMenu, { once: true }); +}; + +// 关闭标签右键菜单 +const closeTagContextMenu = () => { + tagContextMenuVisible.value = false; + // contextTargetTagGroup.value = null; // 保留 targetGroup 直到菜单完全消失,以便动画(如果未来添加) + document.removeEventListener('click', closeTagContextMenu); +}; + +// 处理标签右键菜单操作 +const handleTagMenuAction = (action: 'connectAll') => { + const group = contextTargetTagGroup.value; + closeTagContextMenu(); // 先关闭菜单 + + if (group && action === 'connectAll') { + const sshConnections = group.connections.filter(conn => conn.type === 'SSH'); + + if (sshConnections.length > 0) { + sshConnections.forEach(conn => { + emitWorkspaceEvent('connection:connect', { connectionId: conn.id }); + }); + uiNotificationsStore.addNotification({ + message: t('workspaceConnectionList.connectingAllSshInGroup', { count: sshConnections.length, groupName: group.groupName }), + type: 'info', + }); + } else { + uiNotificationsStore.addNotification({ + message: t('workspaceConnectionList.noSshConnectionsInGroup', { groupName: group.groupName }), + type: 'info', + }); + } + } +}; + // 稍微延迟一下重置,以防是点击列表项导致的失焦 // 如果用户点击了列表项,handleConnect 会先触发 setTimeout(() => { @@ -426,7 +475,7 @@ onBeforeUnmount(() => { // 处理中键点击(在新标签页打开) - 功能已移除 -// 新增:暴露聚焦搜索框的方法 +// 暴露聚焦搜索框的方法 const focusSearchInput = (): boolean => { if (searchInputRef.value) { searchInputRef.value.focus(); @@ -634,6 +683,7 @@ const cancelEditingTag = () => { class="group px-3 py-2 font-semibold flex items-center text-foreground rounded-md hover:bg-header/80 transition-colors duration-150" :class="{ 'cursor-pointer': editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) }" @click="editingTagId !== (groupData.tagId === null ? 'untagged' : groupData.tagId) ? toggleGroup(groupData.groupName) : null" + @contextmenu.prevent="showTagContextMenu($event, groupData)" > { + +
+
    +
  • + + {{ t('workspaceConnectionList.connectAllSshInGroupMenu') }} +
  • +
  • + + {{ t('workspaceConnectionList.noSshConnectionsToConnectMenu') }} +
  • + +
+
+