feat(NetworkConfigManager, SettingsModal): add global PTR zone settings management, allowing users to define DNS replacements in both global and interface-specific contexts for enhanced configuration flexibility
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m47s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m47s
This commit is contained in:
@@ -232,13 +232,30 @@ function NetworkConfigManager() {
|
||||
const [mikrotikCodeModalOpen, setMikrotikCodeModalOpen] = useState(false);
|
||||
const [generatedMikrotikCode, setGeneratedMikrotikCode] = useState([]);
|
||||
|
||||
// === Глобальные настройки PTR зоны ===
|
||||
const [globalPtrZoneReplaceFrom, setGlobalPtrZoneReplaceFrom] = useState('');
|
||||
const [globalPtrZoneReplaceTo, setGlobalPtrZoneReplaceTo] = useState('');
|
||||
|
||||
// === Загрузка данных ===
|
||||
useEffect(() => {
|
||||
fetchConfig();
|
||||
fetchServers();
|
||||
fetchIpsecPasswords();
|
||||
fetchUiSettings();
|
||||
}, []);
|
||||
|
||||
const fetchUiSettings = async () => {
|
||||
try {
|
||||
const response = await api.get('/ui-settings');
|
||||
const data = response.data || {};
|
||||
setGlobalPtrZoneReplaceFrom(String(data?.ptrZoneReplaceFrom || ''));
|
||||
setGlobalPtrZoneReplaceTo(String(data?.ptrZoneReplaceTo || ''));
|
||||
} catch (error) {
|
||||
// Мягко игнорируем ошибку, используем значения по умолчанию
|
||||
console.warn('Не удалось загрузить глобальные настройки PTR зоны:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchConfig = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -1494,14 +1511,20 @@ function NetworkConfigManager() {
|
||||
};
|
||||
|
||||
// Функция для генерации PTR зоны с учетом замены
|
||||
// Приоритет: настройки интерфейса > глобальные настройки
|
||||
const generatePtrZone = (serverDns, iface) => {
|
||||
if (!serverDns) return '—';
|
||||
|
||||
// Если указана замена PTR зоны, применяем её
|
||||
// Сначала проверяем настройки интерфейса
|
||||
if (iface?.ptrZoneReplaceFrom && iface?.ptrZoneReplaceTo) {
|
||||
return serverDns.replace(iface.ptrZoneReplaceFrom, iface.ptrZoneReplaceTo);
|
||||
}
|
||||
|
||||
// Если настройки интерфейса не заданы, используем глобальные настройки
|
||||
if (globalPtrZoneReplaceFrom && globalPtrZoneReplaceTo) {
|
||||
return serverDns.replace(globalPtrZoneReplaceFrom, globalPtrZoneReplaceTo);
|
||||
}
|
||||
|
||||
return serverDns;
|
||||
};
|
||||
|
||||
@@ -1560,7 +1583,7 @@ function NetworkConfigManager() {
|
||||
}
|
||||
return a.type.localeCompare(b.type);
|
||||
});
|
||||
}, [config.tunnelInterfaces, servers]);
|
||||
}, [config.tunnelInterfaces, servers, globalPtrZoneReplaceFrom, globalPtrZoneReplaceTo]);
|
||||
|
||||
// === Фильтрация реестра IP ===
|
||||
const filteredIpRegistry = useMemo(() => {
|
||||
@@ -4254,10 +4277,24 @@ function NetworkConfigManager() {
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{/* Поля для замены PTR зоны */}
|
||||
{/* Поля для замены PTR зоны (опционально, переопределяют глобальные настройки) */}
|
||||
<div className="col-12">
|
||||
<hr />
|
||||
<h6 className="mb-3">Настройка PTR зоны</h6>
|
||||
<h6 className="mb-3">Настройка PTR зоны (опционально)</h6>
|
||||
<div className="alert alert-info alert-dismissible mb-3" role="alert">
|
||||
<div className="small">
|
||||
{globalPtrZoneReplaceFrom && globalPtrZoneReplaceTo ? (
|
||||
<>
|
||||
<strong>Глобальные настройки:</strong> "{globalPtrZoneReplaceFrom}" → "{globalPtrZoneReplaceTo}"<br />
|
||||
Оставьте поля пустыми, чтобы использовать глобальные настройки, или укажите свои значения для переопределения.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Глобальные настройки PTR зоны не заданы. Укажите значения здесь или в разделе "Настройки интерфейса".
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-3">
|
||||
<div className="col-md-6">
|
||||
<FormField
|
||||
@@ -4265,10 +4302,10 @@ function NetworkConfigManager() {
|
||||
name="ptrZoneReplaceFrom"
|
||||
value={editingInterface.ptrZoneReplaceFrom || ''}
|
||||
onChange={(val) => setEditingInterface({ ...editingInterface, ptrZoneReplaceFrom: val })}
|
||||
placeholder="rt.shx"
|
||||
placeholder={globalPtrZoneReplaceFrom || "rt.shx"}
|
||||
/>
|
||||
<div className="form-text">
|
||||
Часть DNS домена, которую нужно заменить (например, "rt.shx")
|
||||
Часть DNS домена, которую нужно заменить (например, "rt.shx"). Оставьте пустым для использования глобальных настроек.
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
@@ -4277,13 +4314,13 @@ function NetworkConfigManager() {
|
||||
name="ptrZoneReplaceTo"
|
||||
value={editingInterface.ptrZoneReplaceTo || ''}
|
||||
onChange={(val) => setEditingInterface({ ...editingInterface, ptrZoneReplaceTo: val })}
|
||||
placeholder="shrt"
|
||||
placeholder={globalPtrZoneReplaceTo || "shrt"}
|
||||
/>
|
||||
<div className="form-text">
|
||||
На что заменить (например, "shrt"). Результат: DNS "selectel.msk.rt.shx.su" → PTR "selectel.msk.shrt.su"
|
||||
На что заменить (например, "shrt"). Оставьте пустым для использования глобальных настроек.
|
||||
</div>
|
||||
</div>
|
||||
{editingInterface.serverId && editingInterface.ptrZoneReplaceFrom && editingInterface.ptrZoneReplaceTo && (() => {
|
||||
{editingInterface.serverId && (editingInterface.ptrZoneReplaceFrom && editingInterface.ptrZoneReplaceTo || globalPtrZoneReplaceFrom && globalPtrZoneReplaceTo) && (() => {
|
||||
const server = getServerInfo(editingInterface.serverId);
|
||||
const originalDns = server?.dns || '';
|
||||
const ptrZone = generatePtrZone(originalDns, editingInterface);
|
||||
@@ -4298,6 +4335,15 @@ function NetworkConfigManager() {
|
||||
<div>
|
||||
<strong>PTR зона:</strong> <code className="text-info">{ptrZone}</code>
|
||||
</div>
|
||||
{editingInterface.ptrZoneReplaceFrom && editingInterface.ptrZoneReplaceTo ? (
|
||||
<div className="text-muted mt-1" style={{ fontSize: '0.75rem' }}>
|
||||
Используются настройки интерфейса
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-muted mt-1" style={{ fontSize: '0.75rem' }}>
|
||||
Используются глобальные настройки
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,8 @@ export default function SettingsModal({ open, onClose }) {
|
||||
const [dohServer, setDohServer] = useState('');
|
||||
const [wsUrl, setWsUrl] = useState('');
|
||||
const [baseAS, setBaseAS] = useState('65001');
|
||||
const [ptrZoneReplaceFrom, setPtrZoneReplaceFrom] = useState('');
|
||||
const [ptrZoneReplaceTo, setPtrZoneReplaceTo] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
@@ -31,6 +33,8 @@ export default function SettingsModal({ open, onClose }) {
|
||||
setDohServer(String(data?.dohServer || ''));
|
||||
setWsUrl(String(data?.wsUpdateUrl || ''));
|
||||
setBaseAS(String(data?.baseAS || '65001'));
|
||||
setPtrZoneReplaceFrom(String(data?.ptrZoneReplaceFrom || ''));
|
||||
setPtrZoneReplaceTo(String(data?.ptrZoneReplaceTo || ''));
|
||||
const e = res?.headers?.etag || res?.headers?.ETag || '';
|
||||
setEtag(e ? String(e) : '');
|
||||
} catch (e) {
|
||||
@@ -90,7 +94,9 @@ export default function SettingsModal({ open, onClose }) {
|
||||
settings: {
|
||||
dohServer: String(dohServer || '').trim(),
|
||||
wsUpdateUrl: String(wsUrl || '').trim(),
|
||||
baseAS: String(baseAS || '65001').trim()
|
||||
baseAS: String(baseAS || '65001').trim(),
|
||||
ptrZoneReplaceFrom: String(ptrZoneReplaceFrom || '').trim(),
|
||||
ptrZoneReplaceTo: String(ptrZoneReplaceTo || '').trim()
|
||||
},
|
||||
etag
|
||||
};
|
||||
@@ -186,6 +192,36 @@ export default function SettingsModal({ open, onClose }) {
|
||||
helpText="AS по умолчанию для community (например, 65001). Используется при поиске и нормализации community."
|
||||
disabled={loading || saving}
|
||||
/>
|
||||
|
||||
<div className="mt-4 pt-3 border-top">
|
||||
<h6 className="mb-3">Настройка PTR зоны</h6>
|
||||
<div className="row g-3">
|
||||
<div className="col-md-6">
|
||||
<FormField
|
||||
label="Заменить в DNS домене"
|
||||
name="ptrZoneReplaceFrom"
|
||||
type="text"
|
||||
value={ptrZoneReplaceFrom}
|
||||
onChange={setPtrZoneReplaceFrom}
|
||||
placeholder="rt.shx"
|
||||
helpText='Часть DNS домена, которую нужно заменить (например, "rt.shx")'
|
||||
disabled={loading || saving}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<FormField
|
||||
label="Заменить на"
|
||||
name="ptrZoneReplaceTo"
|
||||
type="text"
|
||||
value={ptrZoneReplaceTo}
|
||||
onChange={setPtrZoneReplaceTo}
|
||||
placeholder="shrt"
|
||||
helpText='На что заменить (например, "shrt"). Результат: DNS "selectel.msk.rt.shx.su" → PTR "selectel.msk.shrt.su"'
|
||||
disabled={loading || saving}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
|
||||
Reference in New Issue
Block a user