From 489bdedfbb33f78ac5b2d2ef78c42e4469305b35 Mon Sep 17 00:00:00 2001 From: shats Date: Sun, 7 Dec 2025 04:42:38 +0700 Subject: [PATCH] feat: Refactor EasySwitchManager to streamline data loading and enhance community and gateway management, including improved error handling and UI updates for better user experience. --- EASY_SWITCH.md | 15 +++ frontend/src/EasySwitchManager.jsx | 192 +++++++++++++++++++---------- 2 files changed, 139 insertions(+), 68 deletions(-) diff --git a/EASY_SWITCH.md b/EASY_SWITCH.md index 2ed0de1..57718d3 100644 --- a/EASY_SWITCH.md +++ b/EASY_SWITCH.md @@ -186,6 +186,21 @@ GET /api/servers // Метаданные серверов - activeTab: string // Активная вкладка (proxies/providers) ``` +## Важные изменения (v2) + +### ✅ Исправлено в версии 2.0 +- **Все communities отображаются для всех серверов** - больше нет различий в количестве communities между серверами +- **Загрузка названий communities** из справочника `/api/communities` +- **Все gateways сервера** отображаются для каждого community, а не только те, что настроены в filters +- **Бейдж "настроен"** показывает, для каких communities уже есть фильтры +- **Активный gateway берется из filters**, если настроен, иначе выбирается первый + +### Логика работы v2 +1. Загружается справочник communities → **все одинаковые для всех серверов** +2. Для каждого сервера загружаются его gateways (из `/api/servers` или `server-configs`) +3. Для каждого community показываются **все** gateways этого сервера +4. Из filters берется информация только об **активном** gateway для данного community + ## Roadmap ### Планируется добавить diff --git a/frontend/src/EasySwitchManager.jsx b/frontend/src/EasySwitchManager.jsx index fb575dc..f7997d1 100644 --- a/frontend/src/EasySwitchManager.jsx +++ b/frontend/src/EasySwitchManager.jsx @@ -30,6 +30,7 @@ function EasySwitchManager() { // Серверы и фильтры const [servers, setServers] = useState([]); const [inventoryServers, setInventoryServers] = useState([]); + const [communitiesDirectory, setCommunitiesDirectory] = useState([]); // Справочник communities // Поиск и фильтры const [searchQuery, setSearchQuery] = useState(''); @@ -41,20 +42,29 @@ function EasySwitchManager() { const [hasChanges, setHasChanges] = useState(false); useEffect(() => { - loadData(); - loadInventoryServers(); + const initData = async () => { + try { + // Загружаем communities + const commRes = await api.get(`/communities`); + const communities = Array.isArray(commRes.data) ? commRes.data : []; + setCommunitiesDirectory(communities); + + // Загружаем inventory servers + const invRes = await api.get(`/servers`); + const inventory = Array.isArray(invRes.data) ? invRes.data : []; + setInventoryServers(inventory); + + // Загружаем данные серверов и фильтров + await loadDataWithParams(communities, inventory); + } catch (e) { + console.error('Error initializing data:', e); + setError('Ошибка загрузки данных'); + } + }; + initData(); }, []); - const loadInventoryServers = async () => { - try { - const res = await api.get(`/servers`); - setInventoryServers(Array.isArray(res.data) ? res.data : []); - } catch (e) { - console.error('Error loading inventory servers:', e); - } - }; - - const loadData = async () => { + const loadDataWithParams = async (communities, inventory) => { setLoading(true); setError(''); @@ -63,60 +73,84 @@ function EasySwitchManager() { const serversResponse = await api.get(`/server-configs`); const serversList = Array.isArray(serversResponse.data) ? serversResponse.data : []; - // Загружаем фильтры для каждого сервера - const serversWithFilters = await Promise.all( + // Загружаем фильтры для каждого сервера (для определения активных gateways) + const serversWithData = await Promise.all( serversList.map(async (server) => { try { - const response = await api.get(`/server-filters/${server.id}`); - const filters = Array.isArray(response.data) ? response.data : []; + // Загружаем filters для сервера + const filtersResponse = await api.get(`/server-filters/${server.id}`); + const filters = Array.isArray(filtersResponse.data) ? filtersResponse.data : []; - // Группируем фильтры по community внутри сервера - const communitiesMap = new Map(); + // Получаем gateways сервера из inventory или server-configs + const matchedInventoryServer = inventory.find(srv => + String(srv.dns || '').trim() === server.name || + String(srv.hostName || '').trim() === server.name || + String(srv.ip || '').trim() === server.name + ); + + let serverGateways = []; + + // Берем gateways из inventory + if (matchedInventoryServer && Array.isArray(matchedInventoryServer.gateways)) { + serverGateways = matchedInventoryServer.gateways + .filter(gw => gw.name && gw.name !== server.name) + .map(gw => ({ + name: gw.name, + ip: gw.ip || '', + comment: gw.comment || '', + primary: gw.primary || false + })); + } + + // Если нет в inventory, берем из server-configs + if (serverGateways.length === 0 && Array.isArray(server.gateways)) { + serverGateways = server.gateways + .filter(gw => gw.name && gw.name !== server.name) + .map(gw => ({ + name: gw.name, + ip: gw.ip || '', + comment: gw.comment || '', + primary: gw.primary || false + })); + } + + // Создаем map фильтров по community для быстрого поиска + const filtersMap = new Map(); filters.forEach(filter => { - const comm = filter.community; - if (!communitiesMap.has(comm)) { - communitiesMap.set(comm, { - community: comm, - description: filter.description || '', - gateways: [] - }); - } - - const communityData = communitiesMap.get(comm); - // Добавляем gateway, если его еще нет - if (!communityData.gateways.find(g => g.name === filter.gateway)) { - communityData.gateways.push({ - name: filter.gateway, - description: filter.description - }); - } + filtersMap.set(filter.community, filter.gateway); }); return { ...server, - communities: Array.from(communitiesMap.values()) + gateways: serverGateways, + filtersMap: filtersMap }; } catch (e) { - console.error(`Error loading filters for ${server.id}:`, e); + console.error(`Error loading data for ${server.id}:`, e); return { ...server, - communities: [] + gateways: [], + filtersMap: new Map() }; } }) ); - // Фильтруем серверы, у которых есть communities - const serversWithCommunities = serversWithFilters.filter(s => s.communities.length > 0); - setServers(serversWithCommunities); + // Фильтруем серверы, у которых есть gateways + const serversWithGateways = serversWithData.filter(s => s.gateways.length > 0); + setServers(serversWithGateways); - // Устанавливаем активные шлюзы (первый gateway для каждого community на каждом сервере) + // Устанавливаем активные шлюзы из filters или первый gateway const initialActive = {}; - serversWithCommunities.forEach(server => { - server.communities.forEach(comm => { - if (comm.gateways.length > 0) { - const key = `${server.id}:${comm.community}`; - initialActive[key] = comm.gateways[0].name; + serversWithGateways.forEach(server => { + communities.forEach(comm => { + const key = `${server.id}:${comm.value}`; + // Берем gateway из filters, если есть, иначе первый доступный + const gatewayFromFilter = server.filtersMap.get(comm.value); + if (gatewayFromFilter && server.gateways.find(g => g.name === gatewayFromFilter)) { + initialActive[key] = gatewayFromFilter; + } else if (server.gateways.length > 0) { + initialActive[key] = server.gateways[0].name; } }); }); @@ -146,9 +180,24 @@ function EasySwitchManager() { // Здесь можно добавить логику обновления фильтров на серверах }; - const handleRefresh = () => { - loadData(); - loadInventoryServers(); + const handleRefresh = async () => { + try { + // Загружаем communities + const commRes = await api.get(`/communities`); + const communities = Array.isArray(commRes.data) ? commRes.data : []; + setCommunitiesDirectory(communities); + + // Загружаем inventory servers + const invRes = await api.get(`/servers`); + const inventory = Array.isArray(invRes.data) ? invRes.data : []; + setInventoryServers(inventory); + + // Загружаем данные серверов и фильтров + await loadDataWithParams(communities, inventory); + } catch (e) { + console.error('Error refreshing data:', e); + setError('Ошибка обновления данных'); + } }; // Получаем метаданные сервера из inventory @@ -172,14 +221,15 @@ function EasySwitchManager() { if (serverName.includes(search) || serverDesc.includes(search)) return true; // Поиск по communities и gateways - return server.communities.some(comm => { - const commValue = (comm.community || '').toLowerCase(); + return communitiesDirectory.some(comm => { + const commValue = (comm.value || '').toLowerCase(); + const commName = (comm.name || '').toLowerCase(); const commDesc = (comm.description || '').toLowerCase(); return commValue.includes(search) || - commDesc.includes(search) || - comm.gateways.some(g => (g.name || '').toLowerCase().includes(search)); - }); + commName.includes(search) || + commDesc.includes(search); + }) || server.gateways.some(g => (g.name || '').toLowerCase().includes(search)); }); if (loading && servers.length === 0) { @@ -220,7 +270,7 @@ function EasySwitchManager() { Easy Switch
- Быстрое переключение шлюзов для {servers.length} {servers.length === 1 ? 'сервера' : 'серверов'} + Быстрое переключение шлюзов • {servers.length} {servers.length === 1 ? 'сервер' : 'серверов'} • {communitiesDirectory.length} communities
@@ -256,7 +306,7 @@ function EasySwitchManager() { onClick={() => setActiveTab('proxies')} type="button" > - Прокси ({servers.reduce((sum, s) => sum + s.communities.length, 0)}) + Прокси ({communitiesDirectory.length})
  • @@ -363,33 +413,39 @@ function EasySwitchManager() { — {server.description} )} - {server.communities.length} {server.communities.length === 1 ? 'community' : 'communities'} + {communitiesDirectory.length} communities • {server.gateways.length} gateways
  • - {/* Communities для этого сервера */} - {server.communities.map((comm) => { - const activeKey = `${server.id}:${comm.community}`; + {/* ВСЕ Communities для этого сервера */} + {communitiesDirectory.map((comm) => { + const activeKey = `${server.id}:${comm.value}`; const activeGw = activeGateways[activeKey]; + const hasFilterForComm = server.filtersMap.has(comm.value); return ( -
    +
    {/* Заголовок community */}
    - {comm.community} + {comm.value} - {comm.description} + {comm.name || comm.description || ''} + {hasFilterForComm && ( + + настроен + + )} - ({comm.gateways.length}) + ({server.gateways.length})
    - {/* Сетка карточек шлюзов */} + {/* Сетка карточек ВСЕх шлюзов сервера */}
    - {comm.gateways.map((gw, idx) => { + {server.gateways.map((gw, idx) => { const isActive = activeGw === gw.name; const isFastest = idx === 0; const ping = 20 + idx * 10 + Math.floor(Math.random() * 15); @@ -405,7 +461,7 @@ function EasySwitchManager() { borderRadius: '6px', boxShadow: isActive ? '0 3px 8px rgba(32, 107, 196, 0.3)' : 'none' }} - onClick={() => handleGatewaySelect(server.id, comm.community, gw.name)} + onClick={() => handleGatewaySelect(server.id, comm.value, gw.name)} onMouseEnter={(e) => { if (!isActive) { e.currentTarget.style.boxShadow = '0 2px 6px rgba(0,0,0,0.1)';