feat: Обновить менеджеры ASNs, Domains и IPRanges для поддержки серверной пагинации и улучшенной обработки запросов с учетом фильтров и поиска; добавить состояние totalItems для отображения общего количества элементов
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m58s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m58s
This commit is contained in:
@@ -45,6 +45,7 @@ function ASNsNewManager() {
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [itemToDelete, setItemToDelete] = useState(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalItems, setTotalItems] = useState(0);
|
||||
const [sortField, setSortField] = useState('asn');
|
||||
const [sortOrder, setSortOrder] = useState('asc');
|
||||
const [filterCommunity, setFilterCommunity] = useState('');
|
||||
@@ -100,11 +101,14 @@ function ASNsNewManager() {
|
||||
const fetchItems = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await api.get(`/asns`, { params: { offset: 0, limit: 0 } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : (Array.isArray(response.data) ? response.data : []);
|
||||
const effectiveQ = searchTerm ? searchTerm : (filterCommunity ? filterCommunity : '');
|
||||
const response = await api.get(`/asns`, { params: { q: effectiveQ, offset: Math.max(0, (currentPage - 1) * pageSize), limit: pageSize, format: 'std' } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : [];
|
||||
const total = Number(response.data?.total ?? (Array.isArray(response.data) ? response.data.length : 0));
|
||||
const mapped = payload.map(item => ({ asn: item.domain, community: item.type }));
|
||||
setItems(mapped);
|
||||
setOriginalItems(mapped);
|
||||
setTotalItems(Number.isFinite(total) ? total : 0);
|
||||
setEtag(response.headers?.etag || '');
|
||||
setLastModified(response.headers?.['last-modified'] || '');
|
||||
const lengthHeader = response.headers?.['content-length-source'];
|
||||
@@ -118,6 +122,11 @@ function ASNsNewManager() {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchItems();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPage, searchTerm, filterCommunity]);
|
||||
|
||||
const handleAddItem = () => {
|
||||
const asnOk = isValidAsn(newItem.asn);
|
||||
const communityOk = isValidCommunity(newItem.community);
|
||||
@@ -327,14 +336,9 @@ function ASNsNewManager() {
|
||||
? sortedItems.filter(i => i.community === filterCommunity)
|
||||
: sortedItems;
|
||||
|
||||
// Поиск
|
||||
const filteredItems = filteredByCommunity.filter(i =>
|
||||
i.asn.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// Пагинация
|
||||
const totalPages = Math.ceil(filteredItems.length / pageSize);
|
||||
const paginatedItems = filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
// Пагинация теперь серверная
|
||||
const paginatedItems = filteredByCommunity;
|
||||
const totalPages = Math.max(1, Math.ceil((totalItems || paginatedItems.length) / pageSize));
|
||||
|
||||
// Для фильтра - список всех уникальных community
|
||||
const allCommunities = Array.from(new Set(items.map(i => i.community)));
|
||||
@@ -589,7 +593,7 @@ function ASNsNewManager() {
|
||||
{totalPages > 1 && (
|
||||
<div className="card-footer d-flex align-items-center justify-content-between">
|
||||
<div className="text-muted">
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {Math.min(currentPage * pageSize, filteredItems.length)} из {filteredItems.length}
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {((currentPage - 1) * pageSize) + paginatedItems.length} из {totalItems || paginatedItems.length}
|
||||
</div>
|
||||
<ul className="pagination m-0">
|
||||
<li className={`page-item${currentPage === 1 ? ' disabled' : ''}`}>
|
||||
|
||||
@@ -45,6 +45,7 @@ function DomainsNewManager() {
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [itemToDelete, setItemToDelete] = useState(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalItems, setTotalItems] = useState(0);
|
||||
const [sortField, setSortField] = useState('domain');
|
||||
const [sortOrder, setSortOrder] = useState('asc');
|
||||
const [filterCommunity, setFilterCommunity] = useState('');
|
||||
@@ -105,10 +106,13 @@ function DomainsNewManager() {
|
||||
const fetchItems = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await api.get(`/domains-new`, { params: { offset: 0, limit: 0 } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : (Array.isArray(response.data) ? response.data : []);
|
||||
const effectiveQ = searchTerm ? searchTerm : (filterCommunity ? filterCommunity : '');
|
||||
const response = await api.get(`/domains-new`, { params: { q: effectiveQ, offset: Math.max(0, (currentPage - 1) * pageSize), limit: pageSize, format: 'std' } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : [];
|
||||
const total = Number(response.data?.total ?? (Array.isArray(response.data) ? response.data.length : 0));
|
||||
setItems(payload);
|
||||
setOriginalItems(payload);
|
||||
setTotalItems(Number.isFinite(total) ? total : 0);
|
||||
setEtag(response.headers?.etag || '');
|
||||
setLastModified(response.headers?.['last-modified'] || '');
|
||||
const lengthHeader = response.headers?.['content-length-source'];
|
||||
@@ -122,6 +126,12 @@ function DomainsNewManager() {
|
||||
}
|
||||
};
|
||||
|
||||
// Подгрузка при изменении страницы/поиска/фильтра
|
||||
useEffect(() => {
|
||||
fetchItems();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPage, searchTerm, filterCommunity]);
|
||||
|
||||
const handleAddItem = () => {
|
||||
const domainOk = isValidDomain(newItem.domain);
|
||||
const communityOk = isValidCommunity(newItem.community);
|
||||
@@ -329,19 +339,14 @@ function DomainsNewManager() {
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Фильтрация по community
|
||||
const filteredByCommunity = filterCommunity
|
||||
// Дополнительная локальная фильтрация по community только если одновременно задан поиск (сервер фильтрует по q)
|
||||
const filteredByCommunity = searchTerm && filterCommunity
|
||||
? sortedItems.filter(i => i.community === filterCommunity)
|
||||
: sortedItems;
|
||||
|
||||
// Поиск
|
||||
const filteredItems = filteredByCommunity.filter(i =>
|
||||
i.domain.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// Пагинация
|
||||
const totalPages = Math.ceil(filteredItems.length / pageSize);
|
||||
const paginatedItems = filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
// Пагинация теперь серверная: на странице уже items
|
||||
const paginatedItems = filteredByCommunity;
|
||||
const totalPages = Math.max(1, Math.ceil((totalItems || paginatedItems.length) / pageSize));
|
||||
|
||||
// Для фильтра - список всех уникальных community
|
||||
const allCommunities = Array.from(new Set(items.map(i => i.community)));
|
||||
@@ -597,7 +602,7 @@ function DomainsNewManager() {
|
||||
{totalPages > 1 && (
|
||||
<div className="card-footer d-flex align-items-center justify-content-between">
|
||||
<div className="text-muted">
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {Math.min(currentPage * pageSize, filteredItems.length)} из {filteredItems.length}
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {((currentPage - 1) * pageSize) + paginatedItems.length} из {totalItems || paginatedItems.length}
|
||||
</div>
|
||||
<ul className="pagination m-0">
|
||||
<li className={`page-item${currentPage === 1 ? ' disabled' : ''}`}>
|
||||
|
||||
@@ -45,6 +45,7 @@ function IPRangesManager() {
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [itemToDelete, setItemToDelete] = useState(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalItems, setTotalItems] = useState(0);
|
||||
const [sortField, setSortField] = useState('ipRange');
|
||||
const [sortOrder, setSortOrder] = useState('asc');
|
||||
const [filterCommunity, setFilterCommunity] = useState('');
|
||||
@@ -116,10 +117,13 @@ function IPRangesManager() {
|
||||
const fetchItems = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await api.get(`/ip-ranges`, { params: { offset: 0, limit: 0 } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : (Array.isArray(response.data) ? response.data : []);
|
||||
const effectiveQ = searchTerm ? searchTerm : (filterCommunity ? filterCommunity : '');
|
||||
const response = await api.get(`/ip-ranges`, { params: { q: effectiveQ, offset: Math.max(0, (currentPage - 1) * pageSize), limit: pageSize, format: 'std' } });
|
||||
const payload = Array.isArray(response.data?.items) ? response.data.items : [];
|
||||
const total = Number(response.data?.total ?? (Array.isArray(response.data) ? response.data.length : 0));
|
||||
setItems(payload);
|
||||
setOriginalItems(payload);
|
||||
setTotalItems(Number.isFinite(total) ? total : 0);
|
||||
setEtag(response.headers?.etag || '');
|
||||
setLastModified(response.headers?.['last-modified'] || '');
|
||||
const lengthHeader = response.headers?.['content-length-source'];
|
||||
@@ -133,6 +137,11 @@ function IPRangesManager() {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchItems();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPage, searchTerm, filterCommunity]);
|
||||
|
||||
const handleAddItem = () => {
|
||||
const cidrOk = isValidCidr(newItem.ipRange);
|
||||
const communityOk = isValidCommunity(newItem.community);
|
||||
@@ -351,14 +360,9 @@ function IPRangesManager() {
|
||||
? sortedItems.filter(i => i.community === filterCommunity)
|
||||
: sortedItems;
|
||||
|
||||
// Поиск
|
||||
const filteredItems = filteredByCommunity.filter(i =>
|
||||
i.ipRange.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// Пагинация
|
||||
const totalPages = Math.ceil(filteredItems.length / pageSize);
|
||||
const paginatedItems = filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
// Пагинация теперь серверная
|
||||
const paginatedItems = filteredByCommunity;
|
||||
const totalPages = Math.max(1, Math.ceil((totalItems || paginatedItems.length) / pageSize));
|
||||
|
||||
// Для фильтра - список всех уникальных community
|
||||
const allCommunities = Array.from(new Set(items.map(i => i.community)));
|
||||
@@ -857,7 +861,7 @@ function IPRangesManager() {
|
||||
{totalPages > 1 && (
|
||||
<div className="card-footer d-flex align-items-center justify-content-between">
|
||||
<div className="text-muted">
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {Math.min(currentPage * pageSize, filteredItems.length)} из {filteredItems.length}
|
||||
Показано {((currentPage - 1) * pageSize) + 1} - {((currentPage - 1) * pageSize) + paginatedItems.length} из {totalItems || paginatedItems.length}
|
||||
</div>
|
||||
<ul className="pagination m-0">
|
||||
<li className={`page-item${currentPage === 1 ? ' disabled' : ''}`}>
|
||||
|
||||
Reference in New Issue
Block a user