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
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m55s
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user