feat: Add server availability check API and integrate it into the Dashboard and ServerManager components for enhanced server monitoring and user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Has been cancelled
Publish Fast Tabler Docker image / build-and-push-fast (push) Has been cancelled
This commit is contained in:
@@ -15,7 +15,9 @@ import {
|
||||
IconAlertTriangle,
|
||||
IconServer,
|
||||
IconChevronDown,
|
||||
IconLink
|
||||
IconLink,
|
||||
IconFilter,
|
||||
IconMapPin
|
||||
} from '@tabler/icons-react';
|
||||
import GraphView from './GraphView';
|
||||
|
||||
@@ -66,6 +68,11 @@ function ServerManager() {
|
||||
type: 'routes',
|
||||
version: 'v4.rsc'
|
||||
});
|
||||
const presets = {
|
||||
default: { baseUrl: 'https://functions.yandexcloud.net/d4eno3im0qgsr4tj5hdo', cloudflare_gateway: 'SWE-IHOR', bunny_gateway: 'SWE-IHOR', fastly_gateway: 'SWE-IHOR', telegram_gateway: '94.142.140.1', hetzner_gateway: '94.142.140.1', type: 'routes', version: 'v4.rsc' },
|
||||
cloudflareSWE: { baseUrl: 'https://cf.example/api', cloudflare_gateway: 'SWE-IHOR', bunny_gateway: '', fastly_gateway: '', telegram_gateway: '', hetzner_gateway: '', type: 'routes', version: 'v4.rsc' },
|
||||
hetznerDE: { baseUrl: 'https://hetzner.example/api', cloudflare_gateway: '', bunny_gateway: '', fastly_gateway: '', telegram_gateway: '', hetzner_gateway: '94.142.140.1', type: 'routes', version: 'v4.rsc' }
|
||||
};
|
||||
|
||||
// Состояние для мониторинга сети
|
||||
const [networkStatus, setNetworkStatus] = useState({});
|
||||
@@ -81,6 +88,11 @@ function ServerManager() {
|
||||
]);
|
||||
const [newConnection, setNewConnection] = useState({ from: '', to: '', tunnelType: 'GRE', ipA: '', ipB: '' });
|
||||
|
||||
// Фильтры графа
|
||||
const [graphTunnelFilters, setGraphTunnelFilters] = useState({ GRE: true, IPSec: true, WireGuard: true, OpenVPN: true });
|
||||
const [graphCountryFilter, setGraphCountryFilter] = useState('');
|
||||
const [graphProviderFilter, setGraphProviderFilter] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchServers();
|
||||
}, []);
|
||||
@@ -207,6 +219,15 @@ function ServerManager() {
|
||||
return `${urlSettings.baseUrl}?${params.toString()}`;
|
||||
};
|
||||
|
||||
const applyPreset = (name) => {
|
||||
const p = presets[name];
|
||||
if (!p) return;
|
||||
setUrlSettings(prev => ({ ...prev, ...p }));
|
||||
localStorage.setItem('urlSettings', JSON.stringify({ ...urlSettings, ...p }));
|
||||
setSuccess('Профиль применён');
|
||||
setTimeout(() => setSuccess(''), 2000);
|
||||
};
|
||||
|
||||
// Функция резервного копирования для http
|
||||
const fallbackCopyToClipboard = (text) => {
|
||||
const textArea = document.createElement('textarea');
|
||||
@@ -244,9 +265,13 @@ function ServerManager() {
|
||||
};
|
||||
|
||||
const exportAllLinks = () => {
|
||||
const filtered = servers
|
||||
.filter(s => (!filterTunnel || s.tunnel === filterTunnel))
|
||||
.filter(s => (!filterCountry || s.country === filterCountry))
|
||||
.filter(s => (!filterProvider || s.provider === filterProvider));
|
||||
const csvContent = [
|
||||
['IP', 'DNS', 'Country', 'Provider', 'Tunnel', 'Generated URL'],
|
||||
...servers.map(server => [
|
||||
...filtered.map(server => [
|
||||
server.ip,
|
||||
server.dns,
|
||||
server.country,
|
||||
@@ -456,6 +481,17 @@ function ServerManager() {
|
||||
<span className="me-2 d-flex align-items-center"><IconPlus className="icon" /></span>
|
||||
<span className="fw-bold">Добавить</span>
|
||||
</button>
|
||||
{/* Пресеты генератора ссылок */}
|
||||
<div className="dropdown">
|
||||
<button className="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
Профили ссылок
|
||||
</button>
|
||||
<div className="dropdown-menu">
|
||||
{Object.keys(presets).map(key => (
|
||||
<button key={key} className="dropdown-item" type="button" onClick={() => applyPreset(key)}>{key}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary d-flex align-items-center"
|
||||
@@ -705,7 +741,32 @@ function ServerManager() {
|
||||
<div className="text-muted small">Поддержка: GRE, IPSec, WireGuard, OpenVPN</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<GraphView servers={servers} connections={connections} />
|
||||
<div className="mb-3 d-flex flex-wrap gap-2 align-items-center">
|
||||
<span className="text-muted small d-flex align-items-center"><IconFilter size={16} className="me-1" />Фильтры графа:</span>
|
||||
<div className="btn-group btn-group-sm" role="group" aria-label="Туннели">
|
||||
{['GRE','IPSec','WireGuard','OpenVPN'].map(t => (
|
||||
<button key={t} className={`btn ${graphTunnelFilters[t] ? 'btn-primary' : 'btn-outline-primary'}`} onClick={() => setGraphTunnelFilters(prev => ({...prev, [t]: !prev[t]}))}>{t}</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="d-flex align-items-center ms-2">
|
||||
<IconMapPin size={16} className="me-1 text-muted" />
|
||||
<select className="form-select form-select-sm" value={graphCountryFilter} onChange={e => setGraphCountryFilter(e.target.value)}>
|
||||
<option value="">Все страны</option>
|
||||
{Array.from(new Set(servers.map(s => s.country).filter(Boolean))).map(c => (<option key={c} value={c}>{c}</option>))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="d-flex align-items-center">
|
||||
<IconServer size={16} className="me-1 text-muted" />
|
||||
<select className="form-select form-select-sm" value={graphProviderFilter} onChange={e => setGraphProviderFilter(e.target.value)}>
|
||||
<option value="">Все провайдеры</option>
|
||||
{Array.from(new Set(servers.map(s => s.provider).filter(Boolean))).map(p => (<option key={p} value={p}>{p}</option>))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<GraphView
|
||||
servers={servers.filter(s => (!graphCountryFilter || s.country === graphCountryFilter) && (!graphProviderFilter || s.provider === graphProviderFilter))}
|
||||
connections={connections.filter(c => graphTunnelFilters[c.tunnelType])}
|
||||
/>
|
||||
<div className="mt-3">
|
||||
<div className="d-flex align-items-center gap-3 flex-wrap">
|
||||
<div className="d-flex align-items-center gap-2"><span style={{display:'inline-block',width:24,height:4,background:'#206bc4'}}></span><span className="text-muted small">GRE</span></div>
|
||||
|
||||
Reference in New Issue
Block a user