From 905ea93c7f28ffa3d4369e658553b603212f99d4 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Wed, 3 Jun 2026 16:10:47 +0800 Subject: [PATCH] feat: optimize node switch logic for large node sets --- agent/app/service/device_clean.go | 4 +- frontend/src/api/interface/setting.ts | 3 + frontend/src/api/modules/setting.ts | 3 + frontend/src/lang/modules/en.ts | 2 + frontend/src/lang/modules/es-es.ts | 2 + frontend/src/lang/modules/ja.ts | 2 + frontend/src/lang/modules/ko.ts | 2 + frontend/src/lang/modules/ms.ts | 2 + frontend/src/lang/modules/pt-br.ts | 2 + frontend/src/lang/modules/ru.ts | 2 + frontend/src/lang/modules/tr.ts | 2 + frontend/src/lang/modules/zh-Hant.ts | 2 + frontend/src/lang/modules/zh.ts | 2 + .../Sidebar/components/Collapse.vue | 92 +++-- .../Sidebar/components/node-drawer/index.vue | 354 ++++++++++++++++++ 15 files changed, 443 insertions(+), 33 deletions(-) create mode 100644 frontend/src/layout/components/Sidebar/components/node-drawer/index.vue diff --git a/agent/app/service/device_clean.go b/agent/app/service/device_clean.go index 8fcf9344f2c2..5d68c1e52bc3 100644 --- a/agent/app/service/device_clean.go +++ b/agent/app/service/device_clean.go @@ -223,7 +223,7 @@ func doSystemClean(taskItem *task.Task) func(t *task.Task) error { } } - dropWithExclude(path.Join(global.Dir.BaseDir, uploadPath), []string{"theme"}, taskItem, &size, &fileCount) + dropWithExclude(path.Join(global.Dir.BaseDir, uploadPath), []string{"theme", "skills-hub"}, taskItem, &size, &fileCount) dropWithTask(path.Join(global.Dir.BaseDir, downloadPath), taskItem, &size, &fileCount) logFiles, _ := os.ReadDir(global.Dir.LogDir) @@ -863,7 +863,7 @@ func loadTreeWithAllFile(isCheck bool, originalPath, treeType, pathItem string, return lists } for _, file := range files { - if treeType == "upload" && (file.Name() == "theme" && file.IsDir()) { + if treeType == "upload" && ((file.Name() == "theme" || file.Name() == "skills-hub") && file.IsDir()) { continue } if treeType == "system_log" && (file.Name() == "1Panel-Core.log" || file.Name() == "1Panel.log" || file.IsDir()) { diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index d635ac408167..1c25c187e147 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -308,11 +308,14 @@ export namespace Setting { } export interface NodeItem { id: number; + groupID?: number; + groupBelong?: string; addr: string; status: string; version: string; isXpack: boolean; isBound: boolean; + isFavorite?: boolean; name: string; } export interface SimpleNodeItem { diff --git a/frontend/src/api/modules/setting.ts b/frontend/src/api/modules/setting.ts index 28ceb99b4945..ca4cbbffba61 100644 --- a/frontend/src/api/modules/setting.ts +++ b/frontend/src/api/modules/setting.ts @@ -43,6 +43,9 @@ export const loadLicenseOptions = () => { export const listNodeOptions = (type: string) => { return http.post>(`/core/nodes/list`, { type: type }); }; +export const updateNodeFavorite = (id: number, isFavorite: boolean) => { + return http.post(`/core/xpack/nodes/favorite`, { id, isFavorite }); +}; export const listAllSimpleNodes = () => { return http.get>(`/core/nodes/simple/all`); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index cf612e9b591b..6a929fbb75f7 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -5131,6 +5131,8 @@ const message = { memTotal: 'Total Memory', nodeManagement: 'Multi-Machine Management', multiOverview: 'Multi-Machine', + commonNodes: 'Frequently Used Nodes', + searchNodePlaceholder: 'Search node name, group, or address', nodeItem: 'Node Management', panelItem: 'Panel Management', addPanel: 'Add Panel', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index e537bcfb535e..af9825e9409e 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -5182,6 +5182,8 @@ const message = { memTotal: 'Memoria Total', nodeManagement: 'Gestión Multi-Máquina', multiOverview: 'Multimáquina', + commonNodes: 'Nodos frecuentes', + searchNodePlaceholder: 'Buscar nombre, grupo o dirección del nodo', nodeItem: 'Gestión de Nodos', panelItem: 'Gestión de Paneles', addNode: 'Añadir Nodo', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 8eb01f58b21c..c9e9bf6eed73 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -5151,6 +5151,8 @@ const message = { memTotal: '総メモリ', nodeManagement: 'マルチマシン管理', multiOverview: 'マルチマシン', + commonNodes: 'よく使うノード', + searchNodePlaceholder: 'ノード名、グループ、アドレスを検索', nodeItem: 'ノード管理', panelItem: 'パネル管理', addPanel: 'パネル追加', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index cce0a9c8faff..4718650d494f 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -5041,6 +5041,8 @@ const message = { memTotal: '총 메모리', nodeManagement: '다중 머신 관리', multiOverview: '다중 머신', + commonNodes: '자주 사용하는 노드', + searchNodePlaceholder: '노드 이름, 그룹 또는 주소 검색', nodeItem: '노드 관리', panelItem: '패널 관리', addPanel: '패널 추가', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index d8d72fc1c33d..b8f75ac93322 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -5209,6 +5209,8 @@ const message = { memTotal: 'Jumlah Memori', nodeManagement: 'Pengurusan Multi-Mesin', multiOverview: 'Multi-Mesin', + commonNodes: 'Nod Kerap Digunakan', + searchNodePlaceholder: 'Cari nama nod, kumpulan atau alamat', nodeItem: 'Pengurusan Nod', panelItem: 'Pengurusan Panel', addPanel: 'Tambah Panel', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 5ab9314a1e05..393c94d3faf3 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -5357,6 +5357,8 @@ const message = { memTotal: 'Memória Total', nodeManagement: 'Gerenciamento Multi-Máquina', multiOverview: 'Multi-Máquina', + commonNodes: 'Nós frequentes', + searchNodePlaceholder: 'Pesquise nome, grupo ou endereço do nó', nodeItem: 'Gerenciamento de Nós', panelItem: 'Gerenciamento de Painéis', addPanel: 'Adicionar Painel', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 616b22b1e8fe..de6215a4b765 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -5212,6 +5212,8 @@ const message = { memTotal: 'Общая память', nodeManagement: 'Управление Несколькими Машинами', multiOverview: 'Несколько Машин', + commonNodes: 'Часто используемые узлы', + searchNodePlaceholder: 'Поиск по имени узла, группе или адресу', nodeItem: 'Управление Узлами', panelItem: 'Управление Панелями', addPanel: 'Добавить Панель', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index b917f0ec67df..3a8b163a496b 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -5199,6 +5199,8 @@ const message = { memTotal: 'Toplam Bellek', nodeManagement: 'Çoklu Makine Yönetimi', multiOverview: 'Çoklu Makine', + commonNodes: 'Sık Kullanılan Düğümler', + searchNodePlaceholder: 'Düğüm adı, grup veya adres ara', nodeItem: 'Düğüm Yönetimi', panelItem: 'Panel Yönetimi', addPanel: 'Panel Ekle', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 0f42c481ff58..d7006d84d132 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -4773,6 +4773,8 @@ const message = { memTotal: '記憶體總計', nodeManagement: '多機管理', multiOverview: '多機概覽', + commonNodes: '常用節點', + searchNodePlaceholder: '搜尋節點名稱、群組或地址', nodeItem: '節點管理', panelItem: '面板管理', addPanel: '添加面板', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index ff3b797b38a7..7f6dd974b613 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -4224,6 +4224,8 @@ const message = { memTotal: '内存总计', nodeManagement: '多机管理', multiOverview: '多机概览', + commonNodes: '常用节点', + searchNodePlaceholder: '搜索节点名称、分组或地址', nodeItem: '节点管理', panelItem: '面板管理', addPanel: '添加面板', diff --git a/frontend/src/layout/components/Sidebar/components/Collapse.vue b/frontend/src/layout/components/Sidebar/components/Collapse.vue index ff17ae7f3a17..5b4d77b0447d 100644 --- a/frontend/src/layout/components/Sidebar/components/Collapse.vue +++ b/frontend/src/layout/components/Sidebar/components/Collapse.vue @@ -1,6 +1,7 @@ @@ -92,7 +95,7 @@ import { countExecutingTask } from '@/api/modules/log'; import { MsgError, MsgSuccess } from '@/utils/message'; import i18n from '@/lang'; import { getAgentSettingInfo } from '@/api/modules/setting'; -import { onMounted, ref } from 'vue'; +import { computed, onMounted, ref } from 'vue'; import bus from '@/global/bus'; import { logOutApi } from '@/api/modules/auth'; import router from '@/routers'; @@ -102,9 +105,9 @@ import { changeToLocal, listNodes, setDefaultNodeInfo } from '@/utils/node'; import { Login } from '@/api/interface/auth'; import { syncAuthInfo } from '@/utils/rbac'; import UserInfo from './user-info/index.vue'; +import NodeDrawer from './node-drawer/index.vue'; import { useGlobalStore } from '@/composables/useGlobalStore'; -const filter = ref(); const currentUser = ref(); const { globalStore, currentNode, currentNodeAddr, defaultNetwork, entrance, isEnterprise, isXpackOrEE } = useGlobalStore(); @@ -113,11 +116,15 @@ const nodes = ref([]); const nodeOptions = ref([]); const loading = ref(); const switchingNode = ref(false); +const popoverVisible = ref(false); +const nodeDrawerVisible = ref(false); const userInfoRef = ref(); const props = defineProps({ version: String, }); +const defaultNodeLimit = 8; + const emit = defineEmits(['openTask', 'refresh']); bus.on('refreshTask', () => { checkTask(); @@ -133,19 +140,28 @@ const loadCurrentName = () => { return globalStore.getMasterAlias(); }; +const visibleNodeOptions = computed(() => { + return nodeOptions.value.slice(0, defaultNodeLimit); +}); +const showMoreNodes = computed(() => { + return nodeOptions.value.length > defaultNodeLimit; +}); + const showPopover = async () => { - filter.value = ''; await loadNodes(); - changeFilter(); }; -const changeFilter = () => { - nodeOptions.value = []; - for (const item of nodes.value) { - if (item.name.indexOf(filter.value) !== -1) { - nodeOptions.value.push(item); - } - } +const displayNodeName = (item) => { + return item.name === 'local' ? globalStore.getMasterAlias() : item.name; +}; + +const openNodeDrawer = () => { + nodeDrawerVisible.value = true; + popoverVisible.value = false; +}; + +const handleFavoriteChange = async () => { + await loadNodes(); }; const loadNodes = async () => { @@ -162,11 +178,6 @@ const loadNodes = async () => { if (nodes.value.length === 0) { setDefaultNodeInfo(); } - nodes.value.sort((a, b) => { - if (a.name === 'local') return -1; - if (b.name === 'local') return 1; - return 0; - }); nodeOptions.value = nodes.value || []; loading.value = false; }) @@ -362,9 +373,28 @@ onMounted(() => { } } } -.filter-input { - padding: 0 8px; - margin-bottom: 4px; +.node-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.more-node-button { + padding-left: 34px; + color: var(--el-color-primary); +} +.more-node-count { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 20px; + height: 18px; + padding: 0 6px; + border-radius: 9px; + color: var(--el-color-primary); + background: var(--el-color-primary-light-9); + line-height: 18px; } .dropdown-item:hover { background: var(--el-menu-item-bg-color-active); diff --git a/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue b/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue new file mode 100644 index 000000000000..2d3d5d9cb81a --- /dev/null +++ b/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue @@ -0,0 +1,354 @@ + + + + +