feat: Implement add server modal in ServerManager for enhanced server management, including validation and custom provider support
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 17m24s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 17m24s
This commit is contained in:
+2309
File diff suppressed because it is too large
Load Diff
+228
-59
@@ -65,6 +65,14 @@ function ServerManager() {
|
||||
version: 'v4.rsc'
|
||||
});
|
||||
|
||||
// Состояние для мониторинга сети
|
||||
const [networkStatus, setNetworkStatus] = useState({});
|
||||
const [monitoringEnabled, setMonitoringEnabled] = useState(false);
|
||||
|
||||
// Состояние для модального окна добавления сервера
|
||||
const [addServerModalOpen, setAddServerModalOpen] = useState(false);
|
||||
const [customProvider, setCustomProvider] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchServers();
|
||||
}, []);
|
||||
@@ -106,6 +114,44 @@ function ServerManager() {
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
};
|
||||
|
||||
// Функции для модального окна добавления сервера
|
||||
const handleOpenAddServerModal = () => {
|
||||
setAddServerModalOpen(true);
|
||||
};
|
||||
|
||||
const handleCloseAddServerModal = () => {
|
||||
setAddServerModalOpen(false);
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
setCustomProvider('');
|
||||
setError('');
|
||||
};
|
||||
|
||||
const handleAddServerFromModal = () => {
|
||||
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim()) {
|
||||
setError('Все поля должны быть заполнены.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем, если выбран "Другой" провайдер, то customProvider должен быть заполнен
|
||||
if (newServer.provider === 'Другой' && !customProvider.trim()) {
|
||||
setError('Пожалуйста, введите название провайдера.');
|
||||
return;
|
||||
}
|
||||
|
||||
setError('');
|
||||
|
||||
// Используем customProvider если выбран "Другой"
|
||||
const finalProvider = newServer.provider === 'Другой' ? customProvider : newServer.provider;
|
||||
const serverToAdd = { ...newServer, provider: finalProvider };
|
||||
|
||||
setServers([...servers, serverToAdd]);
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
setCustomProvider('');
|
||||
setAddServerModalOpen(false);
|
||||
setSuccess('Сервер успешно добавлен!');
|
||||
setTimeout(() => setSuccess(''), 3000);
|
||||
};
|
||||
|
||||
const handleEdit = (server) => {
|
||||
setEditModalServer({ ...server });
|
||||
setEditModalOpen(true);
|
||||
@@ -354,68 +400,20 @@ function ServerManager() {
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">
|
||||
<IconPlus className="icon me-2" />
|
||||
Добавить новый сервер
|
||||
Управление серверами
|
||||
</h3>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<form onSubmit={(e) => { e.preventDefault(); handleAddServer(); }}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">IP адрес</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="192.168.1.1"
|
||||
value={newServer.ip}
|
||||
onChange={(e) => setNewServer({ ...newServer, ip: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">DNS имя</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="srv1.shx.su"
|
||||
value={newServer.dns}
|
||||
onChange={(e) => setNewServer({ ...newServer, dns: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Страна</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="RU"
|
||||
value={newServer.country}
|
||||
onChange={(e) => setNewServer({ ...newServer, country: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Провайдер</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Yandex"
|
||||
value={newServer.provider}
|
||||
onChange={(e) => setNewServer({ ...newServer, provider: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Тип туннеля</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="GRE"
|
||||
value={newServer.tunnel}
|
||||
onChange={(e) => setNewServer({ ...newServer, tunnel: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-footer">
|
||||
<button type="submit" className="btn btn-primary w-100">
|
||||
<IconPlus className="icon me-2" />
|
||||
Добавить сервер
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="form-footer">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary w-100"
|
||||
onClick={handleOpenAddServerModal}
|
||||
>
|
||||
<IconPlus className="icon me-2" />
|
||||
Добавить новый сервер
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -547,6 +545,8 @@ function ServerManager() {
|
||||
</span>
|
||||
)}
|
||||
</th>
|
||||
<th className="text-center">Основной шлюз</th>
|
||||
<th className="text-center">Статус</th>
|
||||
<th className="text-end">Ссылка</th>
|
||||
<th className="text-end">Действия</th>
|
||||
</tr>
|
||||
@@ -559,6 +559,14 @@ function ServerManager() {
|
||||
<td><span className="badge bg-blue-lt text-blue">{countryToFlag(server.country)} {server.country}</span></td>
|
||||
<td>{server.provider}</td>
|
||||
<td><span className="badge bg-green-lt text-green">{server.tunnel}</span></td>
|
||||
<td className="text-center">
|
||||
<span className="badge bg-blue-lt text-blue">
|
||||
{server.provider}
|
||||
</span>
|
||||
</td>
|
||||
<td className="text-center">
|
||||
<span className="badge bg-success-lt text-success">Онлайн</span>
|
||||
</td>
|
||||
<td className="text-end">
|
||||
<button
|
||||
className="btn btn-outline-info btn-icon"
|
||||
@@ -634,6 +642,18 @@ function ServerManager() {
|
||||
onCopyToClipboard={copyToClipboard}
|
||||
onClose={handleLinkGeneratorClose}
|
||||
/>
|
||||
|
||||
{/* Add Server Modal */}
|
||||
<AddServerModal
|
||||
show={addServerModalOpen}
|
||||
newServer={newServer}
|
||||
customProvider={customProvider}
|
||||
onNewServerChange={setNewServer}
|
||||
onCustomProviderChange={setCustomProvider}
|
||||
onAddServer={handleAddServerFromModal}
|
||||
onClose={handleCloseAddServerModal}
|
||||
error={error}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -934,4 +954,153 @@ function LinkGeneratorModal({ show, server, urlSettings, onUrlSettingsChange, on
|
||||
);
|
||||
}
|
||||
|
||||
// Модальное окно для добавления нового сервера
|
||||
function AddServerModal({ show, newServer, customProvider, onNewServerChange, onCustomProviderChange, onAddServer, onClose, error }) {
|
||||
const modalRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.Tabler && window.Tabler.Modal && modalRef.current) {
|
||||
const modalInstance = window.Tabler.Modal.getOrCreateInstance(modalRef.current);
|
||||
if (show) {
|
||||
modalInstance.show();
|
||||
} else {
|
||||
modalInstance.hide();
|
||||
}
|
||||
const handler = () => onClose && onClose();
|
||||
modalRef.current.addEventListener('hide.bs.modal', handler);
|
||||
return () => {
|
||||
if (modalRef.current) {
|
||||
modalRef.current.removeEventListener('hide.bs.modal', handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [show, onClose]);
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
onNewServerChange({ ...newServer, [field]: value });
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onAddServer();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="modal" tabIndex="-1" ref={modalRef}>
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title">
|
||||
<IconPlus className="icon me-2" />
|
||||
Добавить новый сервер
|
||||
</h5>
|
||||
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{error && (
|
||||
<div className="alert alert-danger" role="alert">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">IP адрес *</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="192.168.1.1"
|
||||
value={newServer.ip}
|
||||
onChange={(e) => handleChange('ip', e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">DNS имя *</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="srv1.shx.su"
|
||||
value={newServer.dns}
|
||||
onChange={(e) => handleChange('dns', e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Страна *</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={newServer.country}
|
||||
onChange={(e) => handleChange('country', e.target.value)}
|
||||
required
|
||||
>
|
||||
<option value="">Выберите страну</option>
|
||||
<option value="RU">Россия (RU)</option>
|
||||
<option value="SWE">Швеция (SWE)</option>
|
||||
<option value="US">США (US)</option>
|
||||
<option value="DE">Германия (DE)</option>
|
||||
<option value="NL">Нидерланды (NL)</option>
|
||||
<option value="SG">Сингапур (SG)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Провайдер *</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={newServer.provider}
|
||||
onChange={(e) => handleChange('provider', e.target.value)}
|
||||
required
|
||||
>
|
||||
<option value="">Выберите провайдера</option>
|
||||
<option value="Yandex">Yandex Cloud</option>
|
||||
<option value="AWS">Amazon Web Services</option>
|
||||
<option value="Google">Google Cloud</option>
|
||||
<option value="Azure">Microsoft Azure</option>
|
||||
<option value="Hetzner">Hetzner</option>
|
||||
<option value="OVH">OVH</option>
|
||||
<option value="DigitalOcean">DigitalOcean</option>
|
||||
<option value="Vultr">Vultr</option>
|
||||
<option value="Linode">Linode</option>
|
||||
<option value="VPSVILLE">VPSVILLE</option>
|
||||
<option value="HIPHOST">HIPHOST</option>
|
||||
<option value="Другой">Другой</option>
|
||||
</select>
|
||||
{newServer.provider === 'Другой' && (
|
||||
<input
|
||||
type="text"
|
||||
className="form-control mt-2"
|
||||
placeholder="Введите название провайдера"
|
||||
value={customProvider}
|
||||
onChange={(e) => onCustomProviderChange(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Тип туннеля *</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={newServer.tunnel}
|
||||
onChange={(e) => handleChange('tunnel', e.target.value)}
|
||||
required
|
||||
>
|
||||
<option value="GRE">GRE (Generic Routing Encapsulation)</option>
|
||||
<option value="IPSec">IPSec</option>
|
||||
<option value="WireGuard">WireGuard</option>
|
||||
<option value="OpenVPN">OpenVPN</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button type="button" className="btn btn-primary" onClick={onAddServer}>
|
||||
<IconPlus className="icon me-2" />
|
||||
Добавить сервер
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ServerManager;
|
||||
Reference in New Issue
Block a user