feat(NetworkConfigManager): add MikroTik code generation for recursive routes; implement modal for previewing and copying generated code
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m43s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m43s
This commit is contained in:
@@ -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() {
|
||||
>
|
||||
<IconRefresh size={16} className={loading ? 'spin' : ''} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary"
|
||||
onClick={handleGenerateMikrotikCode}
|
||||
disabled={loading || (config.gateways || []).filter(gw => gw.type === 'recursive').length === 0}
|
||||
title="Генерировать код MikroTik для рекурсивных маршрутов"
|
||||
>
|
||||
<IconCode size={16} className="me-1" />
|
||||
Код для MikroTik
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
@@ -1512,6 +1615,15 @@ function NetworkConfigManager() {
|
||||
variant="danger"
|
||||
icon={IconTrash}
|
||||
/>
|
||||
|
||||
{/* MikroTik Code Modal */}
|
||||
<PreviewConfigModal
|
||||
show={mikrotikCodeModalOpen}
|
||||
config={generatedMikrotikCode}
|
||||
mode="advanced"
|
||||
onClose={() => setMikrotikCodeModalOpen(false)}
|
||||
onCopy={handleCopyMikrotikCode}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user