fix: Обновление фильтрации и валидации в компонентах ASNsNewManager, AutoUrlManager, DomainsNewManager, IPRangesManager и FilterManager. Добавлена проверка на null для предотвращения ошибок и улучшения стабильности приложения.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m40s

This commit is contained in:
2025-11-06 23:44:18 +07:00
parent 3a41cc394c
commit 216e05df9f
6 changed files with 63 additions and 47 deletions
+12 -11
View File
@@ -218,7 +218,7 @@ function DomainsNewManager() {
const [clearCommunitiesOpen, setClearCommunitiesOpen] = useState(false);
const handlePreviewDiff = () => {
const valid = items.filter(i => isValidDomain(i.domain) && isValidCommunity(i.community))
const valid = items.filter(i => i != null && isValidDomain(i.domain) && isValidCommunity(i.community))
.map(i => ({ domain: i.domain.trim().toLowerCase(), community: String(i.community).trim() }));
const unique = deduplicate(valid);
setDiff(computeDiff(originalItems, unique));
@@ -227,7 +227,7 @@ function DomainsNewManager() {
const handleSaveChanges = async () => {
// подготовим diff и спросим подтверждение только при массовых изменениях (>10)
const valid = items.filter(i => isValidDomain(i.domain) && isValidCommunity(i.community))
const valid = items.filter(i => i != null && isValidDomain(i.domain) && isValidCommunity(i.community))
.map(i => ({ domain: i.domain.trim().toLowerCase(), community: String(i.community).trim() }));
const unique = deduplicate(valid);
const diffData = computeDiff(originalItems, unique);
@@ -256,7 +256,7 @@ function DomainsNewManager() {
// Подгружаем весь список, применяем изменения текущей страницы и сохраняем полные данные
const fullRes = await api.get(`/domains-new`, { params: { offset: 0, limit: 0, format: 'std' } });
const full = Array.isArray(fullRes.data?.items) ? fullRes.data.items : (Array.isArray(fullRes.data) ? fullRes.data : []);
const fullMap = new Map(full.map(i => [String(i.domain).trim().toLowerCase(), { domain: String(i.domain).trim().toLowerCase(), community: String(i.community || '').trim() }]));
const fullMap = new Map(full.filter(i => i != null).map(i => [String(i.domain || '').trim().toLowerCase(), { domain: String(i.domain || '').trim().toLowerCase(), community: String(i.community || '').trim() }]));
const originalPageMap = new Map(originalItems.map(i => [String(i.domain).trim().toLowerCase(), true]));
const uniqueMap = new Map(unique.map(i => [String(i.domain).trim().toLowerCase(), { domain: String(i.domain).trim().toLowerCase(), community: String(i.community).trim() }]));
// Удаления: всё, что было на странице, но отсутствует в изменённом наборе
@@ -300,7 +300,7 @@ function DomainsNewManager() {
const parsed = lines.map(l => {
const [d, c] = l.split(/\s+/);
return { domain: (d || '').toLowerCase(), community: (c || '').trim() };
}).filter(i => isValidDomain(i.domain) && isValidCommunity(i.community));
}).filter(i => i != null && isValidDomain(i.domain) && isValidCommunity(i.community));
setItems(prev => {
const merged = [...prev, ...parsed];
const map = new Map();
@@ -322,7 +322,7 @@ function DomainsNewManager() {
const response = await api.get(`/domains-new`, { params: { q: effectiveQ, offset: 0, limit: 0, format: 'std' } });
const all = Array.isArray(response.data?.items) ? response.data.items : (Array.isArray(response.data) ? response.data : []);
const header = ['domain', 'community'];
const csv = [header, ...all.map(i => [i.domain, i.community])]
const csv = [header, ...all.filter(i => i != null).map(i => [i.domain || '', i.community || ''])]
.map(r => r.map(x => `"${(x ?? '').toString().replace(/"/g, '""')}"`).join(','))
.join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
@@ -338,7 +338,7 @@ function DomainsNewManager() {
};
const clearInvalid = () => {
setItems(prev => prev.filter(i => i.domain || i.community)
setItems(prev => prev.filter(i => i != null && (i.domain || i.community))
.filter(i => isValidDomain(i.domain) && isValidCommunity(i.community))
);
};
@@ -376,16 +376,17 @@ function DomainsNewManager() {
// Локальная фильтрация и пагинация
const filtered = sortedItems.filter(i => {
if (!i) return false;
const byCommunity = !filterCommunity || i.community === filterCommunity;
const term = String(searchTerm || '').toLowerCase();
const bySearch = !term || String(i.domain).toLowerCase().includes(term);
const bySearch = !term || String(i.domain || '').toLowerCase().includes(term);
return byCommunity && bySearch;
});
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
const paginatedItems = filtered.slice((currentPage - 1) * pageSize, (currentPage) * pageSize);
// Для фильтра - список всех уникальных community
const allCommunities = Array.from(new Set(items.map(i => i.community)));
const allCommunities = Array.from(new Set(items.filter(i => i != null).map(i => i.community).filter(c => c != null)));
// Сортировка по клику
const handleSort = (field) => {
@@ -450,8 +451,8 @@ function DomainsNewManager() {
const handleBulkExport = () => {
if (selectedDomains.size === 0) return;
const selectedItems = items.filter(i => selectedDomains.has(i.domain));
const text = selectedItems.map(i => `${i.domain} ${i.community}`).join('\n');
const selectedItems = items.filter(i => i != null && selectedDomains.has(i.domain));
const text = selectedItems.map(i => `${i.domain || ''} ${i.community || ''}`).join('\n');
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
@@ -895,7 +896,7 @@ function DomainsNewManager() {
show={clearCommunitiesOpen}
onClose={() => setClearCommunitiesOpen(false)}
onConfirm={() => {
setItems(prev => prev.filter(i => i.community !== filterCommunity));
setItems(prev => prev.filter(i => i != null && i.community !== filterCommunity));
setClearCommunitiesOpen(false);
}}
title="Удалить записи community?"