diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx
index 40afd81..c607e24 100644
--- a/frontend/src/NetworkConfigManager.jsx
+++ b/frontend/src/NetworkConfigManager.jsx
@@ -5,6 +5,7 @@ import FormModal from './components/FormModal.jsx';
import FormField from './components/FormField.jsx';
import ConfirmModal from './components/ConfirmModal.jsx';
import ServerAutocompleteInput from './components/ServerAutocompleteInput.jsx';
+import PreviewConfigModal from './components/filter/PreviewConfigModal.jsx';
import { countryToFlag } from './utils/serverUtils.js';
import {
IconNetwork,
@@ -22,7 +23,8 @@ import {
IconX,
IconCircleFilled,
IconLayoutGrid,
- IconList
+ IconList,
+ IconCode
} from '@tabler/icons-react';
/**
@@ -125,6 +127,10 @@ function NetworkConfigManager() {
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [itemToDelete, setItemToDelete] = useState(null);
const [deleteType, setDeleteType] = useState('');
+
+ // === MikroTik Code Generation ===
+ const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false);
+ const [generatedMikrotikCode, setGeneratedMikrotikCode] = useState('');
// === Загрузка данных ===
useEffect(() => {
@@ -462,6 +468,93 @@ function NetworkConfigManager() {
}
};
+ // === Генерация кода MikroTik для рекурсивных маршрутов ===
+ const generateMikrotikRecursiveRoutes = () => {
+ const recursiveGateways = (config.gateways || []).filter(gw => gw.type === 'recursive');
+
+ if (recursiveGateways.length === 0) {
+ return '// Нет рекурсивных gateway для генерации маршрутов\n// Добавьте рекурсивные gateway в настройках';
+ }
+
+ let code = '// Конфигурация MikroTik RouterOS для рекурсивных маршрутов\n';
+ code += '// Генерируется автоматически\n';
+ code += `// Дата: ${new Date().toISOString()}\n\n`;
+ code += '# Удаление существующих рекурсивных маршрутов (опционально)\n';
+ code += '/ip route remove [find comment~"Recursive"]\n\n';
+
+ // Группируем по серверам для удобства
+ const gatewaysByServer = {};
+ recursiveGateways.forEach(gw => {
+ const serverId = gw.serverId || '__unassigned__';
+ if (!gatewaysByServer[serverId]) {
+ gatewaysByServer[serverId] = [];
+ }
+ gatewaysByServer[serverId].push(gw);
+ });
+
+ let validRoutesCount = 0;
+
+ Object.entries(gatewaysByServer).forEach(([serverId, gateways]) => {
+ const server = getServerInfo(serverId);
+ const serverName = server?.dns || server?.ip || serverId;
+
+ code += `\n# === Рекурсивные маршруты для сервера: ${serverName} ===\n`;
+
+ gateways.forEach(gw => {
+ const parentGateway = getParentGateway(gw.parentGatewayId);
+
+ if (!parentGateway) {
+ code += `\n# Gateway "${gw.name}" - родительский gateway не найден, пропущен\n`;
+ return;
+ }
+
+ if (!gw.ip) {
+ code += `\n# Gateway "${gw.name}" - IP адрес не указан, пропущен\n`;
+ return;
+ }
+
+ if (!parentGateway.ip) {
+ code += `\n# Gateway "${gw.name}" - родительский gateway "${parentGateway.name}" не имеет IP, пропущен\n`;
+ return;
+ }
+
+ validRoutesCount++;
+
+ // Создаём маршрут для рекурсивного gateway
+ // Маршрут к IP рекурсивного gateway направляется через родительский gateway
+ code += `\n# Рекурсивный gateway: ${gw.name} (IP: ${gw.ip})\n`;
+ code += `# Родительский gateway: ${parentGateway.name} (IP: ${parentGateway.ip})\n`;
+
+ // Создаём маршрут к IP рекурсивного gateway через родительский
+ code += `/ip route add dst-address=${gw.ip}/32 gateway=${parentGateway.ip} comment="Recursive: ${gw.name} -> ${parentGateway.name}"\n`;
+
+ // Если у рекурсивного gateway есть описание с указанием на default route
+ if (gw.description && (gw.description.toLowerCase().includes('default') || gw.description.toLowerCase().includes('0.0.0.0'))) {
+ code += `# Дополнительный default route через рекурсивный gateway\n`;
+ code += `/ip route add dst-address=0.0.0.0/0 gateway=${parentGateway.ip} comment="Recursive default: ${gw.name} -> ${parentGateway.name}"\n`;
+ }
+ });
+ });
+
+ code += '\n# === Проверка созданных маршрутов ===\n';
+ code += '# /ip route print where comment~"Recursive"\n';
+ code += `\n# Всего создано маршрутов: ${validRoutesCount}\n`;
+
+ return code;
+ };
+
+ // === Обработчик кнопки "Код для MikroTik" ===
+ const handleGenerateMikrotikCode = () => {
+ const code = generateMikrotikRecursiveRoutes();
+ setGeneratedMikrotikCode(code);
+ setMikrotikCodeModalOpen(true);
+ };
+
+ // === Копирование кода MikroTik ===
+ const handleCopyMikrotikCode = async () => {
+ await copyToClipboard(generatedMikrotikCode);
+ };
+
// === Получение цвета провайдера ===
const getProviderColor = (provider) => {
if (!provider) return 'secondary';
@@ -754,6 +847,16 @@ function NetworkConfigManager() {
>
+
+
+ {/* MikroTik Code Modal */}
+ setMikrotikCodeModalOpen(false)}
+ onCopy={handleCopyMikrotikCode}
+ />
);
}