feat(ServerManager): implement server grouping in cards view and enhance server modal for groupKey input
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
LinkGeneratorModal,
|
||||
ServerSidebar,
|
||||
ServerCard,
|
||||
ServerGroupCard,
|
||||
ServerBulkActions
|
||||
} from './components/server/index.js';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
@@ -217,9 +218,44 @@ function ServerManager() {
|
||||
return result;
|
||||
}, [servers, filters, searchTerm, sortField, sortOrder]);
|
||||
|
||||
// Элементы для отображения: серверы с одинаковым groupKey (и type home) объединяются в одну карточку
|
||||
const displayItems = useMemo(() => {
|
||||
const keyToServers = {};
|
||||
filteredServers.forEach((s) => {
|
||||
const k = (s.groupKey && String(s.groupKey).trim()) || null;
|
||||
if (k) {
|
||||
if (!keyToServers[k]) keyToServers[k] = [];
|
||||
keyToServers[k].push(s);
|
||||
}
|
||||
});
|
||||
const seenKeys = new Set();
|
||||
const items = [];
|
||||
for (const s of filteredServers) {
|
||||
const k = (s.groupKey && String(s.groupKey).trim()) || null;
|
||||
if (!k) {
|
||||
items.push({ type: 'server', server: s });
|
||||
} else {
|
||||
if (!seenKeys.has(k)) {
|
||||
seenKeys.add(k);
|
||||
const group = keyToServers[k];
|
||||
items.push(group.length >= 2 ? { type: 'group', groupKey: k, servers: group } : { type: 'server', server: group[0] });
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}, [filteredServers]);
|
||||
|
||||
// === Пагинация ===
|
||||
const totalPages = Math.ceil(filteredServers.length / pageSize);
|
||||
const totalPagesCards = Math.ceil(displayItems.length / pageSize);
|
||||
const totalPagesTable = Math.ceil(filteredServers.length / pageSize);
|
||||
const totalPages = viewMode === 'cards' ? totalPagesCards : totalPagesTable;
|
||||
const paginatedDisplayItems = displayItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
const paginatedServers = filteredServers.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
const totalItemsCount = viewMode === 'cards' ? displayItems.length : filteredServers.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPage > totalPages && totalPages >= 1) setCurrentPage(1);
|
||||
}, [viewMode, totalPages]);
|
||||
|
||||
// === Handlers ===
|
||||
const handleSort = (field) => {
|
||||
@@ -252,7 +288,7 @@ function ServerManager() {
|
||||
if (selectedServers.size === filteredServers.length) {
|
||||
setSelectedServers(new Set());
|
||||
} else {
|
||||
setSelectedServers(new Set(filteredServers.map(s => s.ip)));
|
||||
setSelectedServers(new Set(filteredServers.map((s) => s.ip)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -792,18 +828,30 @@ function ServerManager() {
|
||||
</div>
|
||||
</div>
|
||||
) : viewMode === 'cards' ? (
|
||||
/* Cards view */
|
||||
/* Cards view: одиночные серверы и группы (groupKey) */
|
||||
<div>
|
||||
{paginatedServers.map(server => (
|
||||
<ServerCard
|
||||
key={server.id || server.ip}
|
||||
server={server}
|
||||
selected={selectedServers.has(server.ip)}
|
||||
onSelect={toggleServerSelection}
|
||||
onEdit={handleEdit}
|
||||
onDelete={confirmDelete}
|
||||
/>
|
||||
))}
|
||||
{paginatedDisplayItems.map((item) =>
|
||||
item.type === 'group' ? (
|
||||
<ServerGroupCard
|
||||
key={`group-${item.groupKey}`}
|
||||
groupKey={item.groupKey}
|
||||
servers={item.servers}
|
||||
selectedSet={selectedServers}
|
||||
onSelect={toggleServerSelection}
|
||||
onEdit={handleEdit}
|
||||
onDelete={confirmDelete}
|
||||
/>
|
||||
) : (
|
||||
<ServerCard
|
||||
key={item.server.id || item.server.ip}
|
||||
server={item.server}
|
||||
selected={selectedServers.has(item.server.ip)}
|
||||
onSelect={toggleServerSelection}
|
||||
onEdit={handleEdit}
|
||||
onDelete={confirmDelete}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
/* Table view */
|
||||
@@ -892,7 +940,7 @@ function ServerManager() {
|
||||
<div className="card mt-3">
|
||||
<div className="card-footer d-flex align-items-center justify-content-between">
|
||||
<div className="text-muted">
|
||||
{(currentPage - 1) * pageSize + 1} – {Math.min(currentPage * pageSize, filteredServers.length)} из {filteredServers.length}
|
||||
{(currentPage - 1) * pageSize + 1} – {Math.min(currentPage * pageSize, totalItemsCount)} из {totalItemsCount}
|
||||
</div>
|
||||
<ul className="pagination m-0">
|
||||
<li className={`page-item ${currentPage === 1 ? 'disabled' : ''}`}>
|
||||
|
||||
Reference in New Issue
Block a user