refactor: Revamp FilterManager UI for server selection, enhancing layout and interaction with improved card design and search functionality.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m53s

This commit is contained in:
2025-12-06 21:55:29 +07:00
parent 312c442d7c
commit 2b8470a7ca
+67 -64
View File
@@ -900,17 +900,20 @@ function FilterManager() {
</div> </div>
)} )}
{/* Выбор сервера - показываем список когда сервер не выбран */} {/* Селектор серверов на одной странице (Tabler UI) */}
{!selectedServer && ( <div className="card mb-3">
<div className="card">
<div className="card-header"> <div className="card-header">
<h3 className="card-title"> <h3 className="card-title d-flex align-items-center gap-2">
<IconServer className="icon me-2" /> <IconServer className="icon" />
Выберите сервер для работы Серверы
<span className="badge bg-blue-lt text-blue">{servers.length || 0}</span>
{selectedServer && (
<span className="badge bg-green-lt text-green">Выбран: {selectedServer.name}</span>
)}
</h3> </h3>
<div className="card-actions"> <div className="card-actions">
<button <button
className="btn btn-primary" className="btn btn-outline-primary btn-sm"
onClick={() => setServerConfigModalOpen(true)} onClick={() => setServerConfigModalOpen(true)}
> >
<IconPlus className="icon" /> <IconPlus className="icon" />
@@ -939,10 +942,9 @@ function FilterManager() {
</div> </div>
</div> </div>
) : ( ) : (
<> <div className="row g-3">
{/* Поиск */} <div className="col-12 col-lg-4">
<div className="mb-3"> <div className="input-icon mb-2">
<div className="input-icon">
<input <input
type="text" type="text"
className="form-control" className="form-control"
@@ -954,85 +956,86 @@ function FilterManager() {
<IconSearch /> <IconSearch />
</span> </span>
</div> </div>
</div> <div className="list-group list-group-flush border rounded">
{/* Список серверов */}
<div className="row g-3">
{/* Активные серверы */}
{activeServers.length > 0 && ( {activeServers.length > 0 && (
<> <div className="list-group-header px-3 pt-3 pb-2 text-uppercase text-muted small">Активные</div>
<div className="col-12"> )}
<h4 className="text-muted mb-0">Активные серверы</h4>
</div>
{activeServers.map(server => ( {activeServers.map(server => (
<div key={server.id} className="col-md-6 col-lg-4"> <button
<div className="card card-sm card-link" onClick={() => setSelectedServer(server)} style={{ cursor: 'pointer' }}> key={server.id}
<div className="card-body"> className={`list-group-item list-group-item-action d-flex align-items-center ${selectedServer?.id === server.id ? 'active' : ''}`}
<div className="d-flex align-items-center"> onClick={() => setSelectedServer(server)}
<div className="me-3"> >
<span className="avatar bg-primary-lt"> <span className="avatar bg-primary-lt me-3">
<IconServer /> <IconServer size={16} />
</span> </span>
</div> <div className="flex-grow-1 text-start">
<div className="flex-grow-1">
<div className="fw-bold">{server.name}</div> <div className="fw-bold">{server.name}</div>
{server.description && ( {server.description && (
<div className="text-muted small text-truncate" style={{ maxWidth: '200px' }}> <div className="text-muted small text-truncate" style={{ maxWidth: '220px' }}>
{server.description} {server.description}
</div> </div>
)} )}
</div> </div>
<div className="ms-auto">
<span className="badge bg-green-lt text-green">Активен</span> <span className="badge bg-green-lt text-green">Активен</span>
</div> </button>
</div>
</div>
</div>
</div>
))} ))}
</>
)}
{/* Неактивные серверы */}
{inactiveServers.length > 0 && ( {inactiveServers.length > 0 && (
<> <div className="list-group-header px-3 pt-3 pb-2 text-uppercase text-muted small">Неактивные</div>
<div className="col-12 mt-3"> )}
<h4 className="text-muted mb-0">Неактивные серверы</h4>
</div>
{inactiveServers.map(server => ( {inactiveServers.map(server => (
<div key={server.id} className="col-md-6 col-lg-4"> <button
<div className="card card-sm card-link" onClick={() => setSelectedServer(server)} style={{ cursor: 'pointer' }}> key={server.id}
<div className="card-body"> className={`list-group-item list-group-item-action d-flex align-items-center ${selectedServer?.id === server.id ? 'active' : ''}`}
<div className="d-flex align-items-center"> onClick={() => setSelectedServer(server)}
<div className="me-3"> >
<span className="avatar bg-secondary-lt"> <span className="avatar bg-secondary-lt me-3">
<IconServer className="text-muted" /> <IconServer size={16} />
</span> </span>
</div> <div className="flex-grow-1 text-start">
<div className="flex-grow-1"> <div className="fw-bold">{server.name}</div>
<div className="fw-bold text-muted">{server.name}</div>
{server.description && ( {server.description && (
<div className="text-muted small text-truncate" style={{ maxWidth: '200px' }}> <div className="text-muted small text-truncate" style={{ maxWidth: '220px' }}>
{server.description} {server.description}
</div> </div>
)} )}
</div> </div>
<div className="ms-auto"> <span className="badge bg-secondary-lt text-secondary">Выкл</span>
<span className="badge bg-red-lt text-red">Неактивен</span> </button>
</div>
</div>
</div>
</div>
</div>
))} ))}
</> </div>
<div className="mt-2 text-end">
<button
className="btn btn-link px-0 text-decoration-none"
onClick={() => setServerListModalOpen(true)}
>
<IconSettings size={16} className="me-1" />
Управление серверами
</button>
</div>
</div>
<div className="col-12 col-lg-8">
{selectedServer ? (
<div className="alert alert-info d-flex align-items-center" role="alert">
<IconServer className="me-2" />
<div>
Текущий сервер: <span className="fw-bold">{selectedServer.name}</span>
{selectedServer.description && (
<span className="text-muted ms-2">{selectedServer.description}</span>
)} )}
</div> </div>
</> </div>
) : (
<div className="alert alert-warning d-flex align-items-center" role="alert">
<IconAlertTriangle className="me-2" />
<div>Выберите сервер слева, чтобы работать с фильтрами.</div>
</div>
)} )}
</div> </div>
</div> </div>
)} )}
</div>
</div>
{/* Секция фильтров выбранного сервера */} {/* Секция фильтров выбранного сервера */}
{selectedServer && ( {selectedServer && (