feat: Introduce normalization function for community values in CommunitiesManager to ensure consistent formatting and improve input validation across various fields.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
This commit is contained in:
@@ -29,6 +29,13 @@ import Pagination from './components/Pagination.jsx';
|
||||
|
||||
const API_URL = '/api';
|
||||
|
||||
const normalizeCommunityValue = (value) => {
|
||||
const trimmed = String(value || '').trim();
|
||||
if (!trimmed) return '';
|
||||
// Если ASN не указан, используем 65001 по умолчанию
|
||||
return trimmed.includes(':') ? trimmed : `65001:${trimmed}`;
|
||||
};
|
||||
|
||||
function CommunitiesManager() {
|
||||
const [items, setItems] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -93,25 +100,26 @@ function CommunitiesManager() {
|
||||
const usedCommunities = new Set();
|
||||
// ASNs: fields domain/type
|
||||
for (const it of asnsPayload) {
|
||||
const v = String(it.type ?? '').trim();
|
||||
const v = normalizeCommunityValue(it.type);
|
||||
if (v) usedCommunities.add(v);
|
||||
}
|
||||
// IP ranges: fields ipRange/community
|
||||
for (const it of ipPayload) {
|
||||
const v = String(it.community ?? '').trim();
|
||||
const v = normalizeCommunityValue(it.community);
|
||||
if (v) usedCommunities.add(v);
|
||||
}
|
||||
// Domains: fields domain/community
|
||||
for (const it of domPayload) {
|
||||
const v = String(it.community ?? '').trim();
|
||||
const v = normalizeCommunityValue(it.community);
|
||||
if (v) usedCommunities.add(v);
|
||||
}
|
||||
|
||||
const map = new Map();
|
||||
// put dictionary items first
|
||||
for (const d of dict) {
|
||||
const value = String(d.value || '').trim();
|
||||
if (!value) continue;
|
||||
const raw = String(d.value || '').trim();
|
||||
if (!raw) continue;
|
||||
const value = normalizeCommunityValue(raw);
|
||||
map.set(value, {
|
||||
value,
|
||||
name: String(d.name || ''),
|
||||
@@ -159,7 +167,7 @@ function CommunitiesManager() {
|
||||
responses.forEach((res) => {
|
||||
const arr = Array.isArray(res.data) ? res.data : [];
|
||||
arr.forEach((f) => {
|
||||
const value = String(f?.community || '').trim();
|
||||
const value = normalizeCommunityValue(f?.community);
|
||||
if (!value) return;
|
||||
usageMap.set(value, (usageMap.get(value) || 0) + 1);
|
||||
});
|
||||
@@ -194,10 +202,10 @@ function CommunitiesManager() {
|
||||
const fromTagsArray = (arr) => (arr || []).join(', ');
|
||||
|
||||
const addItem = () => {
|
||||
const value = String(newItem.value || '').trim();
|
||||
const value = normalizeCommunityValue(newItem.value);
|
||||
if (!value) { setError('Поле value обязательно.'); return; }
|
||||
if (items.some(i => i.value === value)) { setError('Такое value уже существует.'); return; }
|
||||
if (!/^(\d+|\d+:\d+)$/.test(value)) { setError('Формат: число или N:N'); return; }
|
||||
if (items.some(i => i.value === value)) { setError('Такое value уже существует.'); return; }
|
||||
setError('');
|
||||
setItems([...items, {
|
||||
value,
|
||||
@@ -227,7 +235,7 @@ function CommunitiesManager() {
|
||||
};
|
||||
|
||||
const saveEdit = () => {
|
||||
const value = String(editingDraft.value || '').trim();
|
||||
const value = normalizeCommunityValue(editingDraft.value);
|
||||
if (!value) { setError('Поле value обязательно.'); return; }
|
||||
if (!/^(\d+|\d+:\d+)$/.test(value)) { setError('Формат: число или N:N'); return; }
|
||||
if (value !== editingValue && items.some(i => i.value === value)) { setError('Такое value уже существует.'); return; }
|
||||
@@ -272,7 +280,24 @@ function CommunitiesManager() {
|
||||
try {
|
||||
const arr = JSON.parse(text);
|
||||
if (!Array.isArray(arr)) throw new Error('Ожидается массив');
|
||||
setItems(prev => [...prev, ...arr.filter(x => x && x.value)]);
|
||||
setItems(prev => {
|
||||
const map = new Map(prev.map(i => [i.value, i]));
|
||||
arr.forEach(x => {
|
||||
if (!x || !x.value) return;
|
||||
const norm = normalizeCommunityValue(x.value);
|
||||
if (!norm) return;
|
||||
if (map.has(norm)) return;
|
||||
map.set(norm, {
|
||||
value: norm,
|
||||
name: String(x.name || ''),
|
||||
description: String(x.description || ''),
|
||||
tags: Array.isArray(x.tags) ? x.tags : [],
|
||||
gatewayDefault: String(x.gatewayDefault || ''),
|
||||
color: String(x.color || ''),
|
||||
});
|
||||
});
|
||||
return Array.from(map.values());
|
||||
});
|
||||
} catch (e) {
|
||||
setError('Неверный JSON.');
|
||||
}
|
||||
@@ -655,13 +680,14 @@ function CommunitiesManager() {
|
||||
placeholder="65001:200 или 200 (без указания AS)"
|
||||
required
|
||||
icon={IconHash}
|
||||
helpText="Формат: число (например, 200) или N:N (например, 65001:200)"
|
||||
helpText="Формат: число (например, 200) или N:N (например, 65001:200). Без ASN автоматически станет 65001:XXX."
|
||||
onValidate={(val) => {
|
||||
const trimmed = String(val || '').trim();
|
||||
if (!trimmed) return { valid: false, message: 'Поле обязательно' };
|
||||
if (!/^(\d+|\d+:\d+)$/.test(trimmed)) return { valid: false, message: 'Формат: 200 или 65001:200' };
|
||||
if (items.some(i => i.value === trimmed)) return { valid: false, message: 'Такое value уже существует' };
|
||||
return { valid: true, message: 'Корректно' };
|
||||
const normalized = normalizeCommunityValue(trimmed);
|
||||
if (items.some(i => i.value === normalized)) return { valid: false, message: 'Такое value уже существует' };
|
||||
return { valid: true, message: `Будет сохранено как ${normalized}` };
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -734,15 +760,16 @@ function CommunitiesManager() {
|
||||
placeholder="65001:200 или 200 (без указания AS)"
|
||||
required
|
||||
icon={IconHash}
|
||||
helpText="Формат: число (например, 200) или N:N (например, 65001:200)"
|
||||
helpText="Формат: число (например, 200) или N:N (например, 65001:200). Без ASN автоматически станет 65001:XXX."
|
||||
onValidate={(val) => {
|
||||
const trimmed = String(val || '').trim();
|
||||
if (!trimmed) return { valid: false, message: 'Поле обязательно' };
|
||||
if (!/^(\d+|\d+:\d+)$/.test(trimmed)) return { valid: false, message: 'Формат: 200 или 65001:200' };
|
||||
if (trimmed !== editingValue && items.some(i => i.value === trimmed)) {
|
||||
const normalized = normalizeCommunityValue(trimmed);
|
||||
if (normalized !== editingValue && items.some(i => i.value === normalized)) {
|
||||
return { valid: false, message: 'Такое value уже существует' };
|
||||
}
|
||||
return { valid: true, message: 'Корректно' };
|
||||
return { valid: true, message: `Будет сохранено как ${normalized}` };
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user