feat(MikrotikTools): enhance gateway selection UI with card display and add address format toggle for traceroute results
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 2m56s
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 2m56s
This commit is contained in:
@@ -287,6 +287,72 @@ function MikrotikTools() {
|
|||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Привязка к gateway / интерфейсу (опционально)</label>
|
<label className="form-label">Привязка к gateway / интерфейсу (опционально)</label>
|
||||||
|
{/* Карточки gateways выбранного сервера */}
|
||||||
|
{serverId && gateways.length > 0 && (
|
||||||
|
<div className="mb-2">
|
||||||
|
<div className="row row-cards g-2">
|
||||||
|
{gateways
|
||||||
|
.filter((g) => {
|
||||||
|
if (!g || !g.ip) return false;
|
||||||
|
if (!serverId) return false;
|
||||||
|
if (!currentServer) return g.serverId === serverId;
|
||||||
|
const serverIds = new Set([
|
||||||
|
serverId,
|
||||||
|
currentServer.id,
|
||||||
|
currentServer.ip,
|
||||||
|
currentServer.dns,
|
||||||
|
].filter(Boolean).map(String));
|
||||||
|
return serverIds.has(String(g.serverId));
|
||||||
|
})
|
||||||
|
.map((g) => {
|
||||||
|
const isSelected = gatewayRef === g.ip || gatewayRef === g.id;
|
||||||
|
const flag = g.country ? countryToFlag(g.country) : '';
|
||||||
|
const subtitle = [g.description, g.provider].filter(Boolean).join(' · ');
|
||||||
|
return (
|
||||||
|
<div className="col-12 col-sm-6" key={g.id || g.ip}>
|
||||||
|
<div
|
||||||
|
className={`card card-sm h-100 cursor-pointer ${
|
||||||
|
isSelected ? 'border-primary card-hover' : 'card-hover'
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
const next = isSelected ? '' : (g.ip || g.id);
|
||||||
|
setGatewayRef(next);
|
||||||
|
if (!next) {
|
||||||
|
setGatewayMeta(null);
|
||||||
|
} else {
|
||||||
|
setGatewayMeta({ ip: g.ip, gateway: g });
|
||||||
|
if (!target && g.ip) setTarget(g.ip);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="card-body py-2 px-3 d-flex align-items-start gap-2">
|
||||||
|
<span className="avatar bg-green-lt text-green">
|
||||||
|
{flag || (g.ip ? g.ip.split('.').slice(-1)[0] : '?')}
|
||||||
|
</span>
|
||||||
|
<div className="flex-grow-1 min-w-0">
|
||||||
|
<div className="fw-bold text-truncate" title={g.ip}>
|
||||||
|
{g.ip || '—'}
|
||||||
|
</div>
|
||||||
|
{g.description && (
|
||||||
|
<div className="text-muted small text-truncate" title={g.description}>
|
||||||
|
{g.description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{subtitle && (
|
||||||
|
<div className="text-muted small text-truncate">
|
||||||
|
{subtitle}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Расширенный выбор по IP/интерфейсу */}
|
||||||
<GatewayAutocompleteInput
|
<GatewayAutocompleteInput
|
||||||
value={gatewayRef}
|
value={gatewayRef}
|
||||||
onChange={setGatewayRef}
|
onChange={setGatewayRef}
|
||||||
@@ -297,7 +363,7 @@ function MikrotikTools() {
|
|||||||
onSelectMeta={handleSelectGatewayMeta}
|
onSelectMeta={handleSelectGatewayMeta}
|
||||||
/>
|
/>
|
||||||
<div className="form-text">
|
<div className="form-text">
|
||||||
Можно привязать трассировку к конкретному прямому gateway или туннельному интерфейсу.
|
Можно выбрать gateway карточкой выше или через поиск по IP/интерфейсу.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -340,6 +406,25 @@ function MikrotikTools() {
|
|||||||
onChange={(e) => setMaxHops(e.target.value)}
|
onChange={(e) => setMaxHops(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-2">
|
||||||
|
<label className="form-label">Формат адресов в результатах</label>
|
||||||
|
<div className="form-check form-switch">
|
||||||
|
<input
|
||||||
|
className="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
id="useDnsToggle"
|
||||||
|
checked={useDns}
|
||||||
|
onChange={(e) => setUseDns(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<label className="form-check-label" htmlFor="useDnsToggle">
|
||||||
|
{useDns ? 'DNS + IP (если доступны)' : 'Только IP адреса'}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-text">
|
||||||
|
Этот параметр также передаётся на MikroTik как <code>use-dns</code>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -368,24 +453,7 @@ function MikrotikTools() {
|
|||||||
<div className="col-md-8">
|
<div className="col-md-8">
|
||||||
<div className="card mb-3">
|
<div className="card mb-3">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<h3 className="card-title mb-0">Результаты трассировки</h3>
|
||||||
<h3 className="card-title mb-0">Результаты трассировки</h3>
|
|
||||||
<div className="d-flex align-items-center">
|
|
||||||
<span className="me-2 text-muted small">Отображать</span>
|
|
||||||
<div className="form-check form-switch mb-0">
|
|
||||||
<input
|
|
||||||
className="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
id="useDnsToggle"
|
|
||||||
checked={useDns}
|
|
||||||
onChange={(e) => setUseDns(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<label className="form-check-label small" htmlFor="useDnsToggle">
|
|
||||||
{useDns ? 'DNS + IP' : 'только IP'}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body p-0">
|
<div className="card-body p-0">
|
||||||
{hops.length === 0 ? (
|
{hops.length === 0 ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user