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() {
|
||||
const [servers, setServers] = useState([]);
|
||||
const [newServer, setNewServer] = useState({
|
||||
id: '',
|
||||
ip: '',
|
||||
extIp: '',
|
||||
internalIp: '',
|
||||
dns: '',
|
||||
country: '',
|
||||
provider: '',
|
||||
@@ -132,12 +135,27 @@ function ServerManager() {
|
||||
|
||||
const handleAddServer = () => {
|
||||
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim()) {
|
||||
setError('Все поля должны быть заполнены.');
|
||||
setError('Все обязательные поля должны быть заполнены.');
|
||||
return;
|
||||
}
|
||||
setError('');
|
||||
setServers([...servers, { ...newServer }]);
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
const nextId = `srv-${servers.length + 1}`;
|
||||
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 = () => {
|
||||
setAddServerModalOpen(false);
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
setNewServer({
|
||||
id: '',
|
||||
ip: '',
|
||||
extIp: '',
|
||||
internalIp: '',
|
||||
dns: '',
|
||||
country: '',
|
||||
provider: '',
|
||||
tunnel: 'GRE',
|
||||
gateway: ''
|
||||
});
|
||||
setCustomProvider('');
|
||||
setError('');
|
||||
};
|
||||
|
||||
const handleAddServerFromModal = () => {
|
||||
if (!newServer.ip.trim() || !newServer.dns.trim() || !newServer.country.trim() || !newServer.provider.trim() || !newServer.tunnel.trim() || !newServer.gateway.trim()) {
|
||||
setError('Все поля должны быть заполнены.');
|
||||
setError('Все обязательные поля должны быть заполнены.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -168,10 +196,25 @@ function ServerManager() {
|
||||
|
||||
// Используем customProvider если выбран "Другой"
|
||||
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]);
|
||||
setNewServer({ ip: '', dns: '', country: '', provider: '', tunnel: 'GRE' });
|
||||
setNewServer({
|
||||
id: '',
|
||||
ip: '',
|
||||
extIp: '',
|
||||
internalIp: '',
|
||||
dns: '',
|
||||
country: '',
|
||||
provider: '',
|
||||
tunnel: 'GRE',
|
||||
gateway: ''
|
||||
});
|
||||
setCustomProvider('');
|
||||
setAddServerModalOpen(false);
|
||||
setSuccess('Сервер успешно добавлен!');
|
||||
@@ -188,7 +231,11 @@ function ServerManager() {
|
||||
};
|
||||
|
||||
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);
|
||||
setEditModalServer(null);
|
||||
};
|
||||
@@ -276,9 +323,12 @@ function ServerManager() {
|
||||
.filter(s => (!filterCountry || s.country === filterCountry))
|
||||
.filter(s => (!filterProvider || s.provider === filterProvider));
|
||||
const csvContent = [
|
||||
['IP', 'DNS', 'Country', 'Provider', 'Tunnel', 'Generated URL'],
|
||||
['ID', 'IP', 'Ext IP', 'Internal IP', 'DNS', 'Country', 'Provider', 'Tunnel', 'Generated URL'],
|
||||
...filtered.map(server => [
|
||||
server.id || '',
|
||||
server.ip,
|
||||
server.extIp || '',
|
||||
server.internalIp || '',
|
||||
server.dns,
|
||||
server.country,
|
||||
server.provider,
|
||||
@@ -570,6 +620,12 @@ function ServerManager() {
|
||||
</span>
|
||||
)}
|
||||
</th>
|
||||
<th>
|
||||
Внешний IP
|
||||
</th>
|
||||
<th>
|
||||
Внутренний IP
|
||||
</th>
|
||||
<th className="cursor-pointer" onClick={() => handleSort('dns')}>
|
||||
DNS имя
|
||||
{sortField === 'dns' && (
|
||||
@@ -620,8 +676,10 @@ function ServerManager() {
|
||||
<td colSpan={8} className="text-center text-muted py-4">Ничего не найдено. Измените фильтры или поиск.</td>
|
||||
</tr>
|
||||
) : 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.extIp || <span className="text-muted">—</span>}</td>
|
||||
<td>{server.internalIp || <span className="text-muted">—</span>}</td>
|
||||
<td>{server.dns}</td>
|
||||
<td><span className="badge bg-blue-lt text-blue">{countryToFlag(server.country)} {server.country}</span></td>
|
||||
<td>{server.provider}</td>
|
||||
@@ -761,6 +819,24 @@ function ServerManager() {
|
||||
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
|
||||
label="DNS имя"
|
||||
name="dns"
|
||||
@@ -1066,10 +1142,22 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) {
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<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">
|
||||
<label className="form-label">IP адрес</label>
|
||||
<input type="text" className="form-control" value={localServer.ip || ''} onChange={e => handleChange('ip', e.target.value)} />
|
||||
</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">
|
||||
<label className="form-label">DNS имя</label>
|
||||
<input type="text" className="form-control" value={localServer.dns || ''} onChange={e => handleChange('dns', e.target.value)} />
|
||||
|
||||
Reference in New Issue
Block a user