refactor(FilterManager): streamline server selection UI and enhance button actions for improved user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m55s

This commit is contained in:
2026-02-16 21:07:48 +07:00
parent 5c57e160fd
commit 8ad4f23a49
+9 -131
View File
@@ -14,24 +14,18 @@ import {
IconTrash,
IconCheck,
IconX,
IconDatabase,
IconRefresh,
IconDownload,
IconUpload,
IconAlertTriangle,
IconFilter,
IconChevronDown,
IconLink,
IconCopy,
IconEye,
IconServer,
IconSettings,
IconDeviceFloppy,
IconHash,
IconRocket,
IconSortAscending,
IconSortDescending,
IconWorld,
IconFileText,
IconGripVertical
} from '@tabler/icons-react';
@@ -53,15 +47,6 @@ import {
import { CSS } from '@dnd-kit/utilities';
import { normalizeGateways, countryToFlag } from './utils/serverUtils.js';
import { usePing } from './contexts/PingContext.jsx';
import {
AddFilterModal,
EditFilterModal,
DeleteFilterModal,
PreviewConfigModal,
AddFilterServerModal
} from './components/filter/index.js';
const API_URL = '/api';
// Компонент автокомплита для выбора Community
function CommunityAutocomplete({ label, value, onChange, communities = [], required = false, placeholder = 'Введите или выберите community...', baseAS = '65001' }) {
@@ -1759,122 +1744,6 @@ function FilterManager() {
<PageHeader
title="Управление фильтрами frouting"
icon={<IconFilter size={24} />}
actions={
<div className="btn-list">
<div className="dropdown">
<button
className="btn btn-primary dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<IconServer className="icon" />
{selectedServer ? selectedServer.name : 'Выбрать сервер'}
</button>
<div className="dropdown-menu dropdown-menu-end" style={{ minWidth: '300px' }}>
<div className="px-3 py-2">
<input
type="text"
className="form-control form-control-sm"
placeholder="Поиск серверов..."
value={serverSearch}
onChange={(e) => setServerSearch(e.target.value)}
onClick={(e) => e.stopPropagation()}
/>
</div>
<div className="dropdown-divider"></div>
{activeServers.length > 0 && (
<>
<h6 className="dropdown-header">Активные серверы</h6>
{activeServers.map(server => (
<a
key={server.id}
className={`dropdown-item ${selectedServer?.id === server.id ? 'active' : ''}`}
href="#"
onClick={(e) => {
e.preventDefault();
setSelectedServer(server);
}}
>
<div className="d-flex align-items-center">
<IconServer size={16} className="me-2" />
<span className="flex-grow-1">{server.name}</span>
</div>
</a>
))}
</>
)}
{inactiveServers.length > 0 && (
<>
<div className="dropdown-divider"></div>
<h6 className="dropdown-header">Неактивные серверы</h6>
{inactiveServers.map(server => (
<a
key={server.id}
className={`dropdown-item ${selectedServer?.id === server.id ? 'active' : ''}`}
href="#"
onClick={(e) => {
e.preventDefault();
setSelectedServer(server);
}}
>
<div className="d-flex align-items-center text-muted">
<IconServer size={16} className="me-2" />
<span className="flex-grow-1">{server.name}</span>
</div>
</a>
))}
</>
)}
<div className="dropdown-divider"></div>
<button
className="dropdown-item"
onClick={() => setServerListModalOpen(true)}
>
<IconSettings size={16} className="me-2" />
Управление серверами
</button>
</div>
</div>
{selectedServer && (
<>
<button
className="btn btn-outline-primary"
onClick={handlePreviewConfig}
disabled={serverFilters.length === 0}
>
<IconEye className="icon" />
Просмотр
</button>
<button
className="btn btn-outline-primary"
onClick={copyConfigToClipboard}
disabled={serverFilters.length === 0}
>
<IconCopy className="icon" />
Копировать
</button>
<button
className="btn btn-success"
onClick={() => handleSaveServerConfig(selectedServer.id)}
disabled={loading || serverFilters.length === 0}
>
<IconDeviceFloppy className="icon" />
Сохранить
</button>
<button
className="btn btn-outline-primary"
onClick={handleBgpUpdate}
disabled={bgpUpdateLoading}
title="Запустить /system script run update_bgp_filter на выбранном MikroTik"
>
<IconRefresh className={`icon ${bgpUpdateLoading ? 'spin' : ''}`} />
{bgpUpdateLoading ? 'Запуск...' : 'Обновить BGP фильтры'}
</button>
</>
)}
</div>
}
/>
<div className="page-body">
@@ -1977,6 +1846,15 @@ function FilterManager() {
<IconDeviceFloppy className="icon" />
Сохранить
</button>
<button
className="btn btn-outline-primary"
onClick={handleBgpUpdate}
disabled={!selectedServer || bgpUpdateLoading}
title="Запустить /system script run update_bgp_filter на выбранном MikroTik"
>
<IconRefresh className={`icon ${bgpUpdateLoading ? 'spin' : ''}`} />
{bgpUpdateLoading ? 'Запуск...' : 'Обновить BGP фильтры'}
</button>
</div>
</div>