feat(NetworkConfigManager): add optional interface names for servers; enhance interface name generation logic with DNS parsing and user-defined names
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m41s

This commit is contained in:
2026-01-22 18:56:50 +07:00
parent 011740df1f
commit 39f3510512
+80 -10
View File
@@ -138,6 +138,8 @@ function NetworkConfigManager() {
const [templateServer2, setTemplateServer2] = useState(''); const [templateServer2, setTemplateServer2] = useState('');
const [templateType, setTemplateType] = useState('GRE'); const [templateType, setTemplateType] = useState('GRE');
const [templateNamePrefix, setTemplateNamePrefix] = useState(''); const [templateNamePrefix, setTemplateNamePrefix] = useState('');
const [templateName1, setTemplateName1] = useState(''); // Опциональное имя для сервера 1
const [templateName2, setTemplateName2] = useState(''); // Опциональное имя для сервера 2
// === MikroTik Code Generation === // === MikroTik Code Generation ===
const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false); const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false);
@@ -441,12 +443,44 @@ function NetworkConfigManager() {
}; };
// === Генерация имени интерфейса на основе серверов === // === Генерация имени интерфейса на основе серверов ===
const generateInterfaceName = (server1, server2, type, prefix = '') => { // Для сервера 1: берем часть из DNS сервера 2 (например, msk) и имя хоста сервера 2 (ihor)
const server1Name = server1?.dns?.split('.')[0] || server1?.ip?.split('.').join('-') || 'server1'; // Для сервера 2: берем часть из DNS сервера 1 (например, swe) и имя хоста сервера 1 (hiphost)
const server2Name = server2?.dns?.split('.')[0] || server2?.ip?.split('.').join('-') || 'server2'; const generateInterfaceName = (currentServer, otherServer, type, prefix = '') => {
const typeLower = type.toLowerCase(); // Парсим DNS имена
const parseDnsParts = (dns) => {
if (!dns) return null;
const parts = dns.split('.');
if (parts.length >= 2) {
return {
hostname: parts[0], // первая часть (имя хоста)
location: parts[1] // вторая часть (локация, например msk, swe)
};
}
return null;
};
const currentParts = parseDnsParts(currentServer?.dns);
const otherParts = parseDnsParts(otherServer?.dns);
let name;
if (currentParts && otherParts) {
// Используем локацию из другого сервера и имя хоста из другого сервера
// Например: для сервера 1 (hiphost.swe.shx.su) с сервером 2 (ihor.msk.rt.shx.su)
// Имя на сервере 1: msk-ihor
name = `${otherParts.location}-${otherParts.hostname}`;
} else if (currentServer?.dns) {
// Fallback: используем первую часть DNS
name = currentServer.dns.split('.')[0];
} else if (currentServer?.ip) {
// Fallback: используем IP
name = currentServer.ip.split('.').join('-');
} else {
name = 'server';
}
const prefixPart = prefix ? `${prefix}-` : ''; const prefixPart = prefix ? `${prefix}-` : '';
return `${prefixPart}${typeLower}-${server1Name}-${server2Name}`; return `${prefixPart}${name}`;
}; };
// === Создание интерфейса из шаблона === // === Создание интерфейса из шаблона ===
@@ -469,9 +503,9 @@ function NetworkConfigManager() {
return; return;
} }
// Генерируем имена интерфейсов // Генерируем имена интерфейсов (используем опциональные имена если указаны)
const name1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix); const name1 = templateName1.trim() || generateInterfaceName(server1, server2, templateType, templateNamePrefix);
const name2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix); const name2 = templateName2.trim() || generateInterfaceName(server2, server1, templateType, templateNamePrefix);
// Генерируем IP адреса // Генерируем IP адреса
const localIp = generateFreePrivateIp(null, false, null); const localIp = generateFreePrivateIp(null, false, null);
@@ -518,6 +552,8 @@ function NetworkConfigManager() {
setTemplateServer2(''); setTemplateServer2('');
setTemplateType('GRE'); setTemplateType('GRE');
setTemplateNamePrefix(''); setTemplateNamePrefix('');
setTemplateName1('');
setTemplateName2('');
}; };
// === CRUD для Interfaces === // === CRUD для Interfaces ===
@@ -2749,6 +2785,8 @@ function NetworkConfigManager() {
setTemplateServer2(''); setTemplateServer2('');
setTemplateType('GRE'); setTemplateType('GRE');
setTemplateNamePrefix(''); setTemplateNamePrefix('');
setTemplateName1('');
setTemplateName2('');
}} }}
onSubmit={handleCreateInterfaceFromTemplate} onSubmit={handleCreateInterfaceFromTemplate}
title="Создать интерфейс из шаблона" title="Создать интерфейс из шаблона"
@@ -2819,12 +2857,43 @@ function NetworkConfigManager() {
const server2 = getServerInfo(templateServer2); const server2 = getServerInfo(templateServer2);
if (!server1 || !server2) return null; if (!server1 || !server2) return null;
const previewName1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix); const autoName1 = generateInterfaceName(server1, server2, templateType, templateNamePrefix);
const previewName2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix); const autoName2 = generateInterfaceName(server2, server1, templateType, templateNamePrefix);
const previewName1 = templateName1.trim() || autoName1;
const previewName2 = templateName2.trim() || autoName2;
const previewLocalIp = generateFreePrivateIp(null, false, null); const previewLocalIp = generateFreePrivateIp(null, false, null);
const previewRemoteIp = previewLocalIp ? generateFreePrivateIp(null, true, previewLocalIp) : null; const previewRemoteIp = previewLocalIp ? generateFreePrivateIp(null, true, previewLocalIp) : null;
return ( return (
<>
<div className="col-md-6">
<label className="form-label">
Имя интерфейса (сервер 1)
{!templateName1 && <span className="text-muted small ms-1">(авто: {autoName1})</span>}
</label>
<input
type="text"
className="form-control"
value={templateName1}
onChange={(e) => setTemplateName1(e.target.value)}
placeholder={autoName1}
/>
<div className="form-text">Оставьте пустым для автогенерации</div>
</div>
<div className="col-md-6">
<label className="form-label">
Имя интерфейса (сервер 2)
{!templateName2 && <span className="text-muted small ms-1">(авто: {autoName2})</span>}
</label>
<input
type="text"
className="form-control"
value={templateName2}
onChange={(e) => setTemplateName2(e.target.value)}
placeholder={autoName2}
/>
<div className="form-text">Оставьте пустым для автогенерации</div>
</div>
<div className="col-12"> <div className="col-12">
<div className="card card-sm border"> <div className="card card-sm border">
<div className="card-body"> <div className="card-body">
@@ -2851,6 +2920,7 @@ function NetworkConfigManager() {
</div> </div>
</div> </div>
</div> </div>
</>
); );
})()} })()}
</div> </div>