refactor(NetworkConfigManager): replace action buttons with compact icon buttons wrapped in tooltips for improved UI clarity and user interaction
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m40s

This commit is contained in:
2026-01-25 14:15:39 +07:00
parent 4feb84338a
commit 335f7c9b58
+91 -74
View File
@@ -6,6 +6,7 @@ import FormField from './components/FormField.jsx';
import ConfirmModal from './components/ConfirmModal.jsx';
import ServerAutocompleteInput from './components/ServerAutocompleteInput.jsx';
import GatewayAutocompleteInput from './components/GatewayAutocompleteInput.jsx';
import Tooltip from './components/Tooltip.jsx';
import { countryToFlag } from './utils/serverUtils.js';
import {
IconNetwork,
@@ -2464,22 +2465,26 @@ function NetworkConfigManager() {
</div>
</div>
{/* Правая часть: действия */}
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
<button
className="btn btn-outline-secondary btn-sm"
onClick={() => handleEditPool(pool)}
>
<IconEdit size={16} className="me-1" />
Изменить
</button>
<button
className="btn btn-outline-danger btn-sm"
onClick={() => handleDeletePool(pool)}
>
<IconTrash size={16} className="me-1" />
Удалить
</button>
{/* Правая часть: действия - компактные иконки */}
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
<Tooltip content="Изменить" position="top">
<button
className="btn btn-outline-secondary btn-icon btn-sm"
onClick={() => handleEditPool(pool)}
aria-label="Изменить"
>
<IconEdit size={16} />
</button>
</Tooltip>
<Tooltip content="Удалить" position="top">
<button
className="btn btn-outline-danger btn-icon btn-sm"
onClick={() => handleDeletePool(pool)}
aria-label="Удалить"
>
<IconTrash size={16} />
</button>
</Tooltip>
</div>
</div>
</div>
@@ -2556,12 +2561,12 @@ function NetworkConfigManager() {
<div className="flex-grow-1 py-2 px-3" style={{ minWidth: 0, flex: '1 1 auto', overflow: 'hidden' }}>
{/* Верхняя строка: флаг, название */}
<div className="d-flex align-items-center mb-1">
<div className="d-flex align-items-center" style={{ flex: '0 0 auto', minWidth: 0 }}>
<div className="d-flex align-items-center flex-grow-1" style={{ minWidth: 0 }}>
{displayCountry && (
<span className="me-2" style={{ fontSize: '1.25rem', flexShrink: 0 }}>{countryToFlag(displayCountry)}</span>
<span className="me-2 flex-shrink-0" style={{ fontSize: '1.25rem' }}>{countryToFlag(displayCountry)}</span>
)}
<div>
<span className="fw-semibold">{gateway.description || gateway.ip || '—'}</span>
<div className="flex-grow-1" style={{ minWidth: 0, overflow: 'hidden' }}>
<span className="fw-semibold d-block text-truncate" style={{ maxWidth: '100%' }}>{gateway.description || gateway.ip || '—'}</span>
</div>
</div>
</div>
@@ -2569,7 +2574,7 @@ function NetworkConfigManager() {
{/* Маршрут ip->ip сразу под названием */}
{displayText && (
<div className="mb-1">
<span className="badge bg-success-lt text-success" style={{ whiteSpace: 'nowrap', fontSize: '0.875rem' }}>
<span className="badge bg-success-lt text-success d-inline-block" style={{ fontSize: '0.875rem', maxWidth: '100%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{displayText}
</span>
</div>
@@ -2578,36 +2583,42 @@ function NetworkConfigManager() {
{/* Нижняя строка: DNS */}
<div className="d-flex align-items-center gap-2 flex-wrap">
{server && (
<code className="text-muted" style={{ fontSize: '0.8rem', wordBreak: 'break-all', overflowWrap: 'break-word' }}>
<code className="text-muted d-block text-truncate" style={{ fontSize: '0.8rem', wordBreak: 'break-all', overflowWrap: 'break-word', maxWidth: '100%' }}>
{server.dns || server.ip || gateway.serverId}
</code>
)}
</div>
</div>
{/* Правая часть: действия */}
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
<button
className="btn btn-outline-primary btn-sm"
onClick={() => handleGenerateMikrotikCodeForGateway(gateway)}
>
<IconCode size={16} className="me-1" />
Код
</button>
<button
className="btn btn-outline-secondary btn-sm"
onClick={() => handleEditGateway(gateway)}
>
<IconEdit size={16} className="me-1" />
Изменить
</button>
<button
className="btn btn-outline-danger btn-sm"
onClick={() => handleDeleteGateway(gateway)}
>
<IconTrash size={16} className="me-1" />
Удалить
</button>
{/* Правая часть: действия - компактные иконки */}
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
<Tooltip content="Получить код MikroTik" position="top">
<button
className="btn btn-outline-primary btn-icon btn-sm"
onClick={() => handleGenerateMikrotikCodeForGateway(gateway)}
aria-label="Получить код MikroTik"
>
<IconCode size={16} />
</button>
</Tooltip>
<Tooltip content="Изменить" position="top">
<button
className="btn btn-outline-secondary btn-icon btn-sm"
onClick={() => handleEditGateway(gateway)}
aria-label="Изменить"
>
<IconEdit size={16} />
</button>
</Tooltip>
<Tooltip content="Удалить" position="top">
<button
className="btn btn-outline-danger btn-icon btn-sm"
onClick={() => handleDeleteGateway(gateway)}
aria-label="Удалить"
>
<IconTrash size={16} />
</button>
</Tooltip>
</div>
</div>
</div>
@@ -2682,12 +2693,12 @@ function NetworkConfigManager() {
<div className="flex-grow-1 py-2 px-3" style={{ minWidth: 0, flex: '1 1 auto', overflow: 'hidden' }}>
{/* Верхняя строка: флаг, название */}
<div className="d-flex align-items-center mb-1">
<div className="d-flex align-items-center" style={{ flex: '0 0 auto', minWidth: 0 }}>
<div className="d-flex align-items-center flex-grow-1" style={{ minWidth: 0 }}>
{displayCountry && (
<span className="me-2" style={{ fontSize: '1.25rem', flexShrink: 0 }}>{countryToFlag(displayCountry)}</span>
<span className="me-2 flex-shrink-0" style={{ fontSize: '1.25rem' }}>{countryToFlag(displayCountry)}</span>
)}
<div>
<span className="fw-semibold">{interfaceName}</span>
<div className="flex-grow-1" style={{ minWidth: 0, overflow: 'hidden' }}>
<span className="fw-semibold d-block text-truncate" style={{ maxWidth: '100%' }}>{interfaceName}</span>
</div>
</div>
</div>
@@ -2695,7 +2706,7 @@ function NetworkConfigManager() {
{/* Маршрут между Local IP и Remote IP сразу под названием */}
{displayLocalIp !== '—' && displayRemoteIp !== '—' && (
<div className="mb-1">
<span className="badge bg-success-lt text-success" style={{ whiteSpace: 'nowrap', fontSize: '0.875rem' }}>
<span className="badge bg-success-lt text-success d-inline-block" style={{ fontSize: '0.875rem', maxWidth: '100%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{displayLocalIp} {displayRemoteIp}
</span>
</div>
@@ -2704,36 +2715,42 @@ function NetworkConfigManager() {
{/* Нижняя строка: DNS */}
<div className="d-flex align-items-center gap-2 flex-wrap">
{displayServerName && (
<code className="text-muted" style={{ fontSize: '0.8rem', wordBreak: 'break-all', overflowWrap: 'break-word' }}>
<code className="text-muted d-block text-truncate" style={{ fontSize: '0.8rem', wordBreak: 'break-all', overflowWrap: 'break-word', maxWidth: '100%' }}>
{displayServerName}
</code>
)}
</div>
</div>
{/* Правая часть: действия */}
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
<button
className="btn btn-outline-primary btn-sm"
onClick={() => handleGenerateMikrotikCodeForInterface(iface)}
>
<IconCode size={16} className="me-1" />
Код
</button>
<button
className="btn btn-outline-secondary btn-sm"
onClick={() => handleEditInterface(iface)}
>
<IconEdit size={16} className="me-1" />
Изменить
</button>
<button
className="btn btn-outline-danger btn-sm"
onClick={() => handleDeleteInterface(iface)}
>
<IconTrash size={16} className="me-1" />
Удалить
</button>
{/* Правая часть: действия - компактные иконки */}
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
<Tooltip content="Получить код MikroTik" position="top">
<button
className="btn btn-outline-primary btn-icon btn-sm"
onClick={() => handleGenerateMikrotikCodeForInterface(iface)}
aria-label="Получить код MikroTik"
>
<IconCode size={16} />
</button>
</Tooltip>
<Tooltip content="Изменить" position="top">
<button
className="btn btn-outline-secondary btn-icon btn-sm"
onClick={() => handleEditInterface(iface)}
aria-label="Изменить"
>
<IconEdit size={16} />
</button>
</Tooltip>
<Tooltip content="Удалить" position="top">
<button
className="btn btn-outline-danger btn-icon btn-sm"
onClick={() => handleDeleteInterface(iface)}
aria-label="Удалить"
>
<IconTrash size={16} />
</button>
</Tooltip>
</div>
</div>
</div>