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
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m40s
This commit is contained in:
@@ -6,6 +6,7 @@ import FormField from './components/FormField.jsx';
|
|||||||
import ConfirmModal from './components/ConfirmModal.jsx';
|
import ConfirmModal from './components/ConfirmModal.jsx';
|
||||||
import ServerAutocompleteInput from './components/ServerAutocompleteInput.jsx';
|
import ServerAutocompleteInput from './components/ServerAutocompleteInput.jsx';
|
||||||
import GatewayAutocompleteInput from './components/GatewayAutocompleteInput.jsx';
|
import GatewayAutocompleteInput from './components/GatewayAutocompleteInput.jsx';
|
||||||
|
import Tooltip from './components/Tooltip.jsx';
|
||||||
import { countryToFlag } from './utils/serverUtils.js';
|
import { countryToFlag } from './utils/serverUtils.js';
|
||||||
import {
|
import {
|
||||||
IconNetwork,
|
IconNetwork,
|
||||||
@@ -2464,22 +2465,26 @@ function NetworkConfigManager() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Правая часть: действия */}
|
{/* Правая часть: действия - компактные иконки */}
|
||||||
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
|
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
|
||||||
<button
|
<Tooltip content="Изменить" position="top">
|
||||||
className="btn btn-outline-secondary btn-sm"
|
<button
|
||||||
onClick={() => handleEditPool(pool)}
|
className="btn btn-outline-secondary btn-icon btn-sm"
|
||||||
>
|
onClick={() => handleEditPool(pool)}
|
||||||
<IconEdit size={16} className="me-1" />
|
aria-label="Изменить"
|
||||||
Изменить
|
>
|
||||||
</button>
|
<IconEdit size={16} />
|
||||||
<button
|
</button>
|
||||||
className="btn btn-outline-danger btn-sm"
|
</Tooltip>
|
||||||
onClick={() => handleDeletePool(pool)}
|
<Tooltip content="Удалить" position="top">
|
||||||
>
|
<button
|
||||||
<IconTrash size={16} className="me-1" />
|
className="btn btn-outline-danger btn-icon btn-sm"
|
||||||
Удалить
|
onClick={() => handleDeletePool(pool)}
|
||||||
</button>
|
aria-label="Удалить"
|
||||||
|
>
|
||||||
|
<IconTrash size={16} />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="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 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 && (
|
{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>
|
<div className="flex-grow-1" style={{ minWidth: 0, overflow: 'hidden' }}>
|
||||||
<span className="fw-semibold">{gateway.description || gateway.ip || '—'}</span>
|
<span className="fw-semibold d-block text-truncate" style={{ maxWidth: '100%' }}>{gateway.description || gateway.ip || '—'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2569,7 +2574,7 @@ function NetworkConfigManager() {
|
|||||||
{/* Маршрут ip->ip сразу под названием */}
|
{/* Маршрут ip->ip сразу под названием */}
|
||||||
{displayText && (
|
{displayText && (
|
||||||
<div className="mb-1">
|
<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}
|
{displayText}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -2578,36 +2583,42 @@ function NetworkConfigManager() {
|
|||||||
{/* Нижняя строка: DNS */}
|
{/* Нижняя строка: DNS */}
|
||||||
<div className="d-flex align-items-center gap-2 flex-wrap">
|
<div className="d-flex align-items-center gap-2 flex-wrap">
|
||||||
{server && (
|
{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}
|
{server.dns || server.ip || gateway.serverId}
|
||||||
</code>
|
</code>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Правая часть: действия */}
|
{/* Правая часть: действия - компактные иконки */}
|
||||||
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
|
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
|
||||||
<button
|
<Tooltip content="Получить код MikroTik" position="top">
|
||||||
className="btn btn-outline-primary btn-sm"
|
<button
|
||||||
onClick={() => handleGenerateMikrotikCodeForGateway(gateway)}
|
className="btn btn-outline-primary btn-icon btn-sm"
|
||||||
>
|
onClick={() => handleGenerateMikrotikCodeForGateway(gateway)}
|
||||||
<IconCode size={16} className="me-1" />
|
aria-label="Получить код MikroTik"
|
||||||
Код
|
>
|
||||||
</button>
|
<IconCode size={16} />
|
||||||
<button
|
</button>
|
||||||
className="btn btn-outline-secondary btn-sm"
|
</Tooltip>
|
||||||
onClick={() => handleEditGateway(gateway)}
|
<Tooltip content="Изменить" position="top">
|
||||||
>
|
<button
|
||||||
<IconEdit size={16} className="me-1" />
|
className="btn btn-outline-secondary btn-icon btn-sm"
|
||||||
Изменить
|
onClick={() => handleEditGateway(gateway)}
|
||||||
</button>
|
aria-label="Изменить"
|
||||||
<button
|
>
|
||||||
className="btn btn-outline-danger btn-sm"
|
<IconEdit size={16} />
|
||||||
onClick={() => handleDeleteGateway(gateway)}
|
</button>
|
||||||
>
|
</Tooltip>
|
||||||
<IconTrash size={16} className="me-1" />
|
<Tooltip content="Удалить" position="top">
|
||||||
Удалить
|
<button
|
||||||
</button>
|
className="btn btn-outline-danger btn-icon btn-sm"
|
||||||
|
onClick={() => handleDeleteGateway(gateway)}
|
||||||
|
aria-label="Удалить"
|
||||||
|
>
|
||||||
|
<IconTrash size={16} />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="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 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 && (
|
{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>
|
<div className="flex-grow-1" style={{ minWidth: 0, overflow: 'hidden' }}>
|
||||||
<span className="fw-semibold">{interfaceName}</span>
|
<span className="fw-semibold d-block text-truncate" style={{ maxWidth: '100%' }}>{interfaceName}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2695,7 +2706,7 @@ function NetworkConfigManager() {
|
|||||||
{/* Маршрут между Local IP и Remote IP сразу под названием */}
|
{/* Маршрут между Local IP и Remote IP сразу под названием */}
|
||||||
{displayLocalIp !== '—' && displayRemoteIp !== '—' && (
|
{displayLocalIp !== '—' && displayRemoteIp !== '—' && (
|
||||||
<div className="mb-1">
|
<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}
|
{displayLocalIp} → {displayRemoteIp}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -2704,36 +2715,42 @@ function NetworkConfigManager() {
|
|||||||
{/* Нижняя строка: DNS */}
|
{/* Нижняя строка: DNS */}
|
||||||
<div className="d-flex align-items-center gap-2 flex-wrap">
|
<div className="d-flex align-items-center gap-2 flex-wrap">
|
||||||
{displayServerName && (
|
{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}
|
{displayServerName}
|
||||||
</code>
|
</code>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Правая часть: действия */}
|
{/* Правая часть: действия - компактные иконки */}
|
||||||
<div className="d-flex align-items-center gap-2 px-3 border-start" style={{ flexShrink: 0 }}>
|
<div className="d-flex align-items-center gap-1 px-2 border-start" style={{ flexShrink: 0 }}>
|
||||||
<button
|
<Tooltip content="Получить код MikroTik" position="top">
|
||||||
className="btn btn-outline-primary btn-sm"
|
<button
|
||||||
onClick={() => handleGenerateMikrotikCodeForInterface(iface)}
|
className="btn btn-outline-primary btn-icon btn-sm"
|
||||||
>
|
onClick={() => handleGenerateMikrotikCodeForInterface(iface)}
|
||||||
<IconCode size={16} className="me-1" />
|
aria-label="Получить код MikroTik"
|
||||||
Код
|
>
|
||||||
</button>
|
<IconCode size={16} />
|
||||||
<button
|
</button>
|
||||||
className="btn btn-outline-secondary btn-sm"
|
</Tooltip>
|
||||||
onClick={() => handleEditInterface(iface)}
|
<Tooltip content="Изменить" position="top">
|
||||||
>
|
<button
|
||||||
<IconEdit size={16} className="me-1" />
|
className="btn btn-outline-secondary btn-icon btn-sm"
|
||||||
Изменить
|
onClick={() => handleEditInterface(iface)}
|
||||||
</button>
|
aria-label="Изменить"
|
||||||
<button
|
>
|
||||||
className="btn btn-outline-danger btn-sm"
|
<IconEdit size={16} />
|
||||||
onClick={() => handleDeleteInterface(iface)}
|
</button>
|
||||||
>
|
</Tooltip>
|
||||||
<IconTrash size={16} className="me-1" />
|
<Tooltip content="Удалить" position="top">
|
||||||
Удалить
|
<button
|
||||||
</button>
|
className="btn btn-outline-danger btn-icon btn-sm"
|
||||||
|
onClick={() => handleDeleteInterface(iface)}
|
||||||
|
aria-label="Удалить"
|
||||||
|
>
|
||||||
|
<IconTrash size={16} />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user