diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx
index 7d3fba6..0775a6d 100644
--- a/frontend/src/NetworkConfigManager.jsx
+++ b/frontend/src/NetworkConfigManager.jsx
@@ -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 зоны (опционально, переопределяют глобальные настройки) */}
-
Настройка PTR зоны
+
Настройка PTR зоны (опционально)
+
+
+ {globalPtrZoneReplaceFrom && globalPtrZoneReplaceTo ? (
+ <>
+ Глобальные настройки: "{globalPtrZoneReplaceFrom}" → "{globalPtrZoneReplaceTo}"
+ Оставьте поля пустыми, чтобы использовать глобальные настройки, или укажите свои значения для переопределения.
+ >
+ ) : (
+ <>
+ Глобальные настройки PTR зоны не заданы. Укажите значения здесь или в разделе "Настройки интерфейса".
+ >
+ )}
+
+
setEditingInterface({ ...editingInterface, ptrZoneReplaceFrom: val })}
- placeholder="rt.shx"
+ placeholder={globalPtrZoneReplaceFrom || "rt.shx"}
/>
- Часть DNS домена, которую нужно заменить (например, "rt.shx")
+ Часть DNS домена, которую нужно заменить (например, "rt.shx"). Оставьте пустым для использования глобальных настроек.
@@ -4277,13 +4314,13 @@ function NetworkConfigManager() {
name="ptrZoneReplaceTo"
value={editingInterface.ptrZoneReplaceTo || ''}
onChange={(val) => setEditingInterface({ ...editingInterface, ptrZoneReplaceTo: val })}
- placeholder="shrt"
+ placeholder={globalPtrZoneReplaceTo || "shrt"}
/>
- На что заменить (например, "shrt"). Результат: DNS "selectel.msk.rt.shx.su" → PTR "selectel.msk.shrt.su"
+ На что заменить (например, "shrt"). Оставьте пустым для использования глобальных настроек.
- {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() {
PTR зона: {ptrZone}
+ {editingInterface.ptrZoneReplaceFrom && editingInterface.ptrZoneReplaceTo ? (
+
+ Используются настройки интерфейса
+
+ ) : (
+
+ Используются глобальные настройки
+
+ )}
diff --git a/frontend/src/components/SettingsModal.jsx b/frontend/src/components/SettingsModal.jsx
index c4fbd0d..fb4240a 100644
--- a/frontend/src/components/SettingsModal.jsx
+++ b/frontend/src/components/SettingsModal.jsx
@@ -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}
/>
+
+