From cc77a21ba18ae4ab6c5c312c80dda8cc0b0a926e Mon Sep 17 00:00:00 2001 From: shats Date: Sun, 25 Jan 2026 12:26:26 +0700 Subject: [PATCH] feat(NetworkConfigManager): add server-wide MikroTik code generation for interfaces, improving bulk configuration capabilities and user feedback --- frontend/src/NetworkConfigManager.jsx | 180 ++++++++++++++++++++------ 1 file changed, 137 insertions(+), 43 deletions(-) diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index 380c149..814668e 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -1836,6 +1836,62 @@ function NetworkConfigManager() { } }; + // === Генерация кода MikroTik для всех интерфейсов сервера === + const handleGenerateMikrotikCodeForServer = async (serverId, type) => { + if (!serverId) { + notify.error('Сервер не указан'); + return; + } + + setLoading(true); + try { + if (type === 'interface') { + // Получаем все интерфейсы для этого сервера (где сервер участвует как первый или второй) + // Фильтруем только те, где оба сервера указаны и есть IP адреса + const serverInterfaces = (config.tunnelInterfaces || []).filter(iface => + (iface.serverId === serverId || iface.serverId2 === serverId) && + iface.serverId && iface.serverId2 && iface.localIp && iface.remoteIp + ); + + if (serverInterfaces.length === 0) { + notify.error('Нет интерфейсов с полной конфигурацией для этого сервера'); + setLoading(false); + return; + } + + const blocks = await generateMikrotikInterfaceAddressesForSelection(serverInterfaces); + if (!blocks || blocks.length === 0) { + notify.error('Нет данных для генерации кода MikroTik для этого сервера'); + setLoading(false); + return; + } + + // Фильтруем блоки, чтобы показать только те, что относятся к данному серверу + const server = getServerInfo(serverId); + const serverName = server?.dns || server?.ip || serverId; + const filteredBlocks = blocks.filter(block => + block.serverName === serverName || block.server?.id === serverId + ); + + if (filteredBlocks.length === 0) { + notify.error('Не удалось сгенерировать код для этого сервера'); + setLoading(false); + return; + } + + setGeneratedMikrotikCode(filteredBlocks); + setMikrotikCodeModalOpen(true); + } else { + notify.error('Генерация кода для gateways по серверу пока не реализована'); + } + } catch (error) { + console.error('Error generating MikroTik code for server:', error); + notify.error('Ошибка при генерации кода MikroTik для этого сервера'); + } finally { + setLoading(false); + } + }; + // === Генерация кода MikroTik только для одного интерфейса === const handleGenerateMikrotikCodeForInterface = async (iface) => { if (!iface) { @@ -2186,55 +2242,93 @@ function NetworkConfigManager() { const isUnassigned = serverId === '__unassigned__'; return ( -
- {/* Server header */} -
-
- {isUnassigned ? ( - <> - - - - Без привязки к серверу - - ) : ( - <> - - - -
- - {server?.dns ? server.dns.split('.')[0] : (server?.name || serverId)} +
+ {/* Server header - более заметный и читаемый */} +
+
+
+ {isUnassigned ? ( + <> + + - {server?.dns && ( - - {server.dns} - - )} - {server && ( - - {server.ip} - {server.country && ( - {countryToFlag(server.country)} {server.country} +
+

Без привязки к серверу

+
+ + ) : ( + <> + + + +
+
+

+ {server?.dns ? server.dns.split('.')[0] : (server?.name || serverId)} +

+ {server?.dns && ( + + {server.dns} + )} - - )} -
- - )} + {server?.ip && ( + + {server.ip} + + )} + {server?.country && ( + + {countryToFlag(server.country)} {server.country} + + )} + {server?.provider && ( + + {server.provider} + + )} +
+
+ + )} +
+
+ + {items.length} {type === 'gateway' ? (items.length === 1 ? 'gateway' : 'gateways') : (items.length === 1 ? 'интерфейс' : 'интерфейсов')} + + {type === 'interface' && !isUnassigned && items.length > 0 && ( + + )} +
- {items.length}
{/* Items */} -
- {items.map(item => ( -
- {type === 'gateway' ? renderGatewayCard(item) : - type === 'interface' ? renderInterfaceCard(item, serverId) : - type === 'pool' ? renderPoolCard(item) : null} -
- ))} +
+
+ {items.map(item => ( +
+ {type === 'gateway' ? renderGatewayCard(item) : + type === 'interface' ? renderInterfaceCard(item, serverId) : + type === 'pool' ? renderPoolCard(item) : null} +
+ ))} +
);