From c25011e72b7fd44081bdc6b17ab7d4a04d10eee8 Mon Sep 17 00:00:00 2001 From: Denis Shatskiy Date: Mon, 14 Jul 2025 10:53:12 +0700 Subject: [PATCH] feat: Add functionality to copy server configuration to all servers and deploy configuration to enabled servers in FilterManager for improved server management --- frontend/src/FilterManager.jsx | 191 +++++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 23 deletions(-) diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index a426e2b..401d8a2 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -165,6 +165,142 @@ function FilterManager() { } }; + const handleCopyConfigToAllServers = async (sourceServerId) => { + const sourceServer = servers.find(s => s.id === sourceServerId); + if (!sourceServer) { + setError('Исходный сервер не найден.'); + return; + } + + const targetServers = servers.filter(s => s.id !== sourceServerId && s.enabled); + if (targetServers.length === 0) { + setError('Нет других активных серверов для копирования конфигурации.'); + return; + } + + const confirm = window.confirm( + `Скопировать конфигурацию с сервера "${sourceServer.name}" на ${targetServers.length} сервер(ов)?\n\n` + + `Целевые серверы: ${targetServers.map(s => s.name).join(', ')}` + ); + + if (!confirm) return; + + setLoading(true); + try { + // Получаем конфигурацию исходного сервера + const sourceResponse = await axios.get(`${API_URL}/server-configs/${sourceServerId}`); + const sourceConfig = sourceResponse.data.config; + + if (!sourceConfig || sourceConfig === '// Конфигурация не найдена') { + setError(`У сервера "${sourceServer.name}" нет сохраненной конфигурации.`); + return; + } + + const results = []; + + // Копируем конфигурацию на все целевые серверы + for (const targetServer of targetServers) { + try { + await axios.post(`${API_URL}/server-configs/${targetServer.id}`, { config: sourceConfig }); + results.push({ server: targetServer.name, status: 'success' }); + } catch (error) { + console.error(`Error copying config to ${targetServer.name}:`, error); + results.push({ server: targetServer.name, status: 'error', error: error.message }); + } + } + + const successCount = results.filter(r => r.status === 'success').length; + const errorCount = results.filter(r => r.status === 'error').length; + + if (errorCount === 0) { + setSuccess(`Конфигурация успешно скопирована на ${successCount} сервер(ов)!`); + } else { + setError( + `Копирование завершено с ошибками:\n` + + `✅ Успешно: ${successCount}\n` + + `❌ Ошибки: ${errorCount}\n\n` + + `Ошибки:\n` + + results.filter(r => r.status === 'error') + .map(r => `• ${r.server}: ${r.error}`) + .join('\n') + ); + } + + setTimeout(() => { + setSuccess(''); + setError(''); + }, 8000); + } catch (error) { + console.error('Error copying config to all servers:', error); + setError('Не удалось скопировать конфигурацию на серверы.'); + } finally { + setLoading(false); + } + }; + + const handleDeployToAllServers = async () => { + if (servers.length === 0) { + setError('Нет серверов для развертывания.'); + return; + } + + const enabledServers = servers.filter(s => s.enabled); + if (enabledServers.length === 0) { + setError('Нет включенных серверов для развертывания.'); + return; + } + + const confirm = window.confirm( + `Вы уверены, что хотите развернуть конфигурацию на ${enabledServers.length} сервер(ов)?\n\n` + + `Серверы: ${enabledServers.map(s => s.name).join(', ')}` + ); + + if (!confirm) return; + + setLoading(true); + try { + const config = await generateMikrotikConfig(); + const results = []; + + for (const server of enabledServers) { + try { + await axios.post(`${API_URL}/server-configs/${server.id}`, { config }); + results.push({ server: server.name, status: 'success' }); + } catch (error) { + console.error(`Error deploying to ${server.name}:`, error); + results.push({ server: server.name, status: 'error', error: error.message }); + } + } + + const successCount = results.filter(r => r.status === 'success').length; + const errorCount = results.filter(r => r.status === 'error').length; + + if (errorCount === 0) { + setSuccess(`Конфигурация успешно развернута на ${successCount} сервер(ов)!`); + } else { + setError( + `Развертывание завершено с ошибками:\n` + + `✅ Успешно: ${successCount}\n` + + `❌ Ошибки: ${errorCount}\n\n` + + `Ошибки:\n` + + results.filter(r => r.status === 'error') + .map(r => `• ${r.server}: ${r.error}`) + .join('\n') + ); + } + + setTimeout(() => { + setSuccess(''); + setError(''); + }, 8000); + } catch (error) { + console.error('Error deploying to all servers:', error); + setError('Не удалось развернуть конфигурацию на серверы.'); + } finally { + setLoading(false); + } + }; + const handleAddFilter = () => { if (!newFilter.community.trim() || !newFilter.gateway.trim()) { setError('Поля Community и Gateway должны быть заполнены.'); @@ -511,29 +647,38 @@ function FilterManager() { {server.description && (

{server.description}

)} -
- - - -
+
+ + + + +