feat: Enhance ServerManager component by adding optional external and internal IP fields, improving server addition and editing functionality, and updating validation messages for better user experience.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m45s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m45s
This commit is contained in:
@@ -31,7 +31,10 @@ const API_URL = '/api';
|
|||||||
function ServerManager() {
|
function ServerManager() {
|
||||||
const [servers, setServers] = useState([]);
|
const [servers, setServers] = useState([]);
|
||||||
const [newServer, setNewServer] = useState({
|
const [newServer, setNewServer] = useState({
|
||||||
|
id: '',
|
||||||
ip: '',
|
ip: '',
|
||||||
|
extIp: '',
|
||||||
|
internalIp: '',
|
||||||
dns: '',
|
dns: '',
|
||||||
country: '',
|
country: '',
|
||||||
provider: '',
|
provider: '',
|
||||||
@@ -132,12 +135,27 @@ function ServerManager() {
|
|||||||
|
|
||||||
const handleAddServer = () => {
|
const handleAddServer = () => {
|
||||||
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim()) {
|
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim()) {
|
||||||
setError('Все поля должны быть заполнены.');
|
setError('Все обязательные поля должны быть заполнены.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setError('');
|
setError('');
|
||||||
setServers([...servers, { ...newServer }]);
|
const nextId = `srv-${servers.length + 1}`;
|
||||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
const serverToAdd = {
|
||||||
|
...newServer,
|
||||||
|
id: newServer.id || nextId,
|
||||||
|
};
|
||||||
|
setServers([...servers, serverToAdd]);
|
||||||
|
setNewServer({
|
||||||
|
id: '',
|
||||||
|
ip: '',
|
||||||
|
extIp: '',
|
||||||
|
internalIp: '',
|
||||||
|
dns: '',
|
||||||
|
country: '',
|
||||||
|
provider: '',
|
||||||
|
tunnel: 'GRE',
|
||||||
|
gateway: ''
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Функции для модального окна добавления сервера
|
// Функции для модального окна добавления сервера
|
||||||
@@ -147,14 +165,24 @@ function ServerManager() {
|
|||||||
|
|
||||||
const handleCloseAddServerModal = () => {
|
const handleCloseAddServerModal = () => {
|
||||||
setAddServerModalOpen(false);
|
setAddServerModalOpen(false);
|
||||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
setNewServer({
|
||||||
|
id: '',
|
||||||
|
ip: '',
|
||||||
|
extIp: '',
|
||||||
|
internalIp: '',
|
||||||
|
dns: '',
|
||||||
|
country: '',
|
||||||
|
provider: '',
|
||||||
|
tunnel: 'GRE',
|
||||||
|
gateway: ''
|
||||||
|
});
|
||||||
setCustomProvider('');
|
setCustomProvider('');
|
||||||
setError('');
|
setError('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddServerFromModal = () => {
|
const handleAddServerFromModal = () => {
|
||||||
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim() || !newServer.gateway.trim()) {
|
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim() || !newServer.gateway.trim()) {
|
||||||
setError('Все поля должны быть заполнены.');
|
setError('Все обязательные поля должны быть заполнены.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,10 +196,25 @@ function ServerManager() {
|
|||||||
|
|
||||||
// Используем customProvider если выбран "Другой"
|
// Используем customProvider если выбран "Другой"
|
||||||
const finalProvider = newServer.provider === 'Другой' ? customProvider : newServer.provider;
|
const finalProvider = newServer.provider === 'Другой' ? customProvider : newServer.provider;
|
||||||
const serverToAdd = { ...newServer, provider: finalProvider };
|
const nextId = `srv-${servers.length + 1}`;
|
||||||
|
const serverToAdd = {
|
||||||
|
...newServer,
|
||||||
|
provider: finalProvider,
|
||||||
|
id: newServer.id || nextId,
|
||||||
|
};
|
||||||
|
|
||||||
setServers([...servers, serverToAdd]);
|
setServers([...servers, serverToAdd]);
|
||||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
setNewServer({
|
||||||
|
id: '',
|
||||||
|
ip: '',
|
||||||
|
extIp: '',
|
||||||
|
internalIp: '',
|
||||||
|
dns: '',
|
||||||
|
country: '',
|
||||||
|
provider: '',
|
||||||
|
tunnel: 'GRE',
|
||||||
|
gateway: ''
|
||||||
|
});
|
||||||
setCustomProvider('');
|
setCustomProvider('');
|
||||||
setAddServerModalOpen(false);
|
setAddServerModalOpen(false);
|
||||||
setSuccess('Сервер успешно добавлен!');
|
setSuccess('Сервер успешно добавлен!');
|
||||||
@@ -188,7 +231,11 @@ function ServerManager() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleEditModalSave = (updatedServer) => {
|
const handleEditModalSave = (updatedServer) => {
|
||||||
setServers(servers.map(s => s.ip === updatedServer.ip ? { ...updatedServer } : s));
|
setServers(servers.map(s => {
|
||||||
|
const sameId = s.id && updatedServer.id ? s.id === updatedServer.id : false;
|
||||||
|
const sameIp = s.ip === updatedServer.ip;
|
||||||
|
return (sameId || sameIp) ? { ...s, ...updatedServer } : s;
|
||||||
|
}));
|
||||||
setEditModalOpen(false);
|
setEditModalOpen(false);
|
||||||
setEditModalServer(null);
|
setEditModalServer(null);
|
||||||
};
|
};
|
||||||
@@ -276,9 +323,12 @@ function ServerManager() {
|
|||||||
.filter(s => (!filterCountry || s.country === filterCountry))
|
.filter(s => (!filterCountry || s.country === filterCountry))
|
||||||
.filter(s => (!filterProvider || s.provider === filterProvider));
|
.filter(s => (!filterProvider || s.provider === filterProvider));
|
||||||
const csvContent = [
|
const csvContent = [
|
||||||
['IP', 'DNS', 'Country', 'Provider', 'Tunnel', 'Generated URL'],
|
['ID', 'IP', 'Ext IP', 'Internal IP', 'DNS', 'Country', 'Provider', 'Tunnel', 'Generated URL'],
|
||||||
...filtered.map(server => [
|
...filtered.map(server => [
|
||||||
|
server.id || '',
|
||||||
server.ip,
|
server.ip,
|
||||||
|
server.extIp || '',
|
||||||
|
server.internalIp || '',
|
||||||
server.dns,
|
server.dns,
|
||||||
server.country,
|
server.country,
|
||||||
server.provider,
|
server.provider,
|
||||||
@@ -570,6 +620,12 @@ function ServerManager() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</th>
|
</th>
|
||||||
|
<th>
|
||||||
|
Внешний IP
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Внутренний IP
|
||||||
|
</th>
|
||||||
<th className="cursor-pointer" onClick={() => handleSort('dns')}>
|
<th className="cursor-pointer" onClick={() => handleSort('dns')}>
|
||||||
DNS имя
|
DNS имя
|
||||||
{sortField === 'dns' && (
|
{sortField === 'dns' && (
|
||||||
@@ -620,8 +676,10 @@ function ServerManager() {
|
|||||||
<td colSpan={8} className="text-center text-muted py-4">Ничего не найдено. Измените фильтры или поиск.</td>
|
<td colSpan={8} className="text-center text-muted py-4">Ничего не найдено. Измените фильтры или поиск.</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : paginatedServers.map((server) => (
|
) : paginatedServers.map((server) => (
|
||||||
<tr key={server.ip} className={editingServer === server.ip ? 'table-info' : ''}>
|
<tr key={server.id || server.ip} className={editingServer === server.ip ? 'table-info' : ''}>
|
||||||
<td>{server.ip}</td>
|
<td>{server.ip}</td>
|
||||||
|
<td>{server.extIp || <span className="text-muted">—</span>}</td>
|
||||||
|
<td>{server.internalIp || <span className="text-muted">—</span>}</td>
|
||||||
<td>{server.dns}</td>
|
<td>{server.dns}</td>
|
||||||
<td><span className="badge bg-blue-lt text-blue">{countryToFlag(server.country)} {server.country}</span></td>
|
<td><span className="badge bg-blue-lt text-blue">{countryToFlag(server.country)} {server.country}</span></td>
|
||||||
<td>{server.provider}</td>
|
<td>{server.provider}</td>
|
||||||
@@ -761,6 +819,24 @@ function ServerManager() {
|
|||||||
helpText="Введите IPv4 адрес сервера"
|
helpText="Введите IPv4 адрес сервера"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
label="Внешний IP (опционально)"
|
||||||
|
name="extIp"
|
||||||
|
value={newServer.extIp}
|
||||||
|
onChange={(val) => setNewServer({ ...newServer, extIp: val })}
|
||||||
|
placeholder="Публичный IP, если отличается"
|
||||||
|
icon={IconServer}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
label="Внутренний IP (опционально)"
|
||||||
|
name="internalIp"
|
||||||
|
value={newServer.internalIp}
|
||||||
|
onChange={(val) => setNewServer({ ...newServer, internalIp: val })}
|
||||||
|
placeholder="10.x.x.x / 192.168.x.x"
|
||||||
|
icon={IconServer}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
label="DNS имя"
|
label="DNS имя"
|
||||||
name="dns"
|
name="dns"
|
||||||
@@ -1066,10 +1142,22 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
<form onSubmit={e => { e.preventDefault(); onSave && onSave(localServer); }}>
|
<form onSubmit={e => { e.preventDefault(); onSave && onSave(localServer); }}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">ID (опционально)</label>
|
||||||
|
<input type="text" className="form-control" value={localServer.id || ''} onChange={e => handleChange('id', e.target.value)} placeholder="srv-1" />
|
||||||
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">IP адрес</label>
|
<label className="form-label">IP адрес</label>
|
||||||
<input type="text" className="form-control" value={localServer.ip || ''} onChange={e => handleChange('ip', e.target.value)} />
|
<input type="text" className="form-control" value={localServer.ip || ''} onChange={e => handleChange('ip', e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Внешний IP (опционально)</label>
|
||||||
|
<input type="text" className="form-control" value={localServer.extIp || ''} onChange={e => handleChange('extIp', e.target.value)} placeholder="публичный IP, если отличается" />
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Внутренний IP (опционально)</label>
|
||||||
|
<input type="text" className="form-control" value={localServer.internalIp || ''} onChange={e => handleChange('internalIp', e.target.value)} placeholder="10.x.x.x / 192.168.x.x" />
|
||||||
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">DNS имя</label>
|
<label className="form-label">DNS имя</label>
|
||||||
<input type="text" className="form-control" value={localServer.dns || ''} onChange={e => handleChange('dns', e.target.value)} />
|
<input type="text" className="form-control" value={localServer.dns || ''} onChange={e => handleChange('dns', e.target.value)} />
|
||||||
|
|||||||
Reference in New Issue
Block a user