From 61f0db7b03becb56a8ea687ccf5da39e18eb7abc Mon Sep 17 00:00:00 2001 From: shats Date: Wed, 27 Aug 2025 18:27:58 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=20AccordionCard=20=D0=B2=20=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=B4=D0=B6=D0=B5=D1=80=D1=8B=20ASNs,=20Domains=20=D0=B8=20IPR?= =?UTF-8?q?anges=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D0=B0=20=D0=B2=D0=B2=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D0=B8=20=D1=84=D1=83=D0=BD?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D1=82=D0=B0?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D0=BC?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/ASNsNewManager.jsx | 47 ++++++++++++++--------- frontend/src/DomainsNewManager.jsx | 47 ++++++++++++++--------- frontend/src/IPRangesManager.jsx | 47 ++++++++++++++--------- frontend/src/components/AccordionCard.jsx | 23 +++++++++++ frontend/src/components/PageHeader.jsx | 2 +- 5 files changed, 111 insertions(+), 55 deletions(-) create mode 100644 frontend/src/components/AccordionCard.jsx diff --git a/frontend/src/ASNsNewManager.jsx b/frontend/src/ASNsNewManager.jsx index 93b1ca4..2aaca7b 100644 --- a/frontend/src/ASNsNewManager.jsx +++ b/frontend/src/ASNsNewManager.jsx @@ -31,6 +31,7 @@ import ErrorAlert from './components/ErrorAlert.jsx'; import { notifyMutationSuccess } from './components/NotifyProvider.jsx'; import ImportModal from './components/ImportModal.jsx'; import QuickAddBar from './components/QuickAddBar.jsx'; +import AccordionCard from './components/AccordionCard.jsx'; const API_URL = '/api'; @@ -523,24 +524,34 @@ function ASNsNewManager() { - {/* QuickAdd stays for batch input */} - { const [a, c] = String(line).split(/\s+/); return { asn: (a||'').trim(), community: (c||'').trim() }; }} - validateItem={(obj) => isValidAsn(obj.asn) && isValidCommunity(obj.community)} - onApply={(list) => { - setItems(prev => { - const merged = [...prev, ...list]; - const map = new Map(); - for (const it of merged) { - const key = String(it.asn).trim(); - if (!map.has(key)) map.set(key, { asn: key, community: String(it.community).trim() }); - } - return Array.from(map.values()); - }); - }} - /> + {/* Дополнительные варианты */} + + { const [a, c] = String(line).split(/\s+/); return { asn: (a||'').trim(), community: (c||'').trim() }; }} + validateItem={(obj) => isValidAsn(obj.asn) && isValidCommunity(obj.community)} + onApply={(list) => { + setItems(prev => { + const merged = [...prev, ...list]; + const map = new Map(); + for (const it of merged) { + const key = String(it.asn).trim(); + if (!map.has(key)) map.set(key, { asn: key, community: String(it.community).trim() }); + } + return Array.from(map.values()); + }); + }} + /> +
{ e.preventDefault(); }} + onDrop={onDropImport} + > +
+ Перетащите файл TXT/CSV сюда для импорта (формат: ASN community) +
+
+
{/* Drag & Drop импорт */}
- {/* QuickAdd stays for batch input */} - { const [d, c] = String(line).split(/\s+/); return { domain: (d||'').toLowerCase(), community: (c||'').trim() }; }} - validateItem={(obj) => isValidDomain(obj.domain) && isValidCommunity(obj.community)} - onApply={(list) => { - setItems(prev => { - const merged = [...prev, ...list]; - const map = new Map(); - for (const it of merged) { - const key = String(it.domain).trim().toLowerCase(); - if (!map.has(key)) map.set(key, { domain: key, community: String(it.community).trim() }); - } - return Array.from(map.values()); - }); - }} - /> + {/* Дополнительные варианты */} + + { const [d, c] = String(line).split(/\s+/); return { domain: (d||'').toLowerCase(), community: (c||'').trim() }; }} + validateItem={(obj) => isValidDomain(obj.domain) && isValidCommunity(obj.community)} + onApply={(list) => { + setItems(prev => { + const merged = [...prev, ...list]; + const map = new Map(); + for (const it of merged) { + const key = String(it.domain).trim().toLowerCase(); + if (!map.has(key)) map.set(key, { domain: key, community: String(it.community).trim() }); + } + return Array.from(map.values()); + }); + }} + /> +
{ e.preventDefault(); }} + onDrop={onDropImport} + > +
+ Перетащите файл TXT/CSV сюда для импорта (формат: domain community) +
+
+
{/* Карточка действий больше не нужна — действия перенесены в page-header */} {/* Drag & Drop импорт */} diff --git a/frontend/src/IPRangesManager.jsx b/frontend/src/IPRangesManager.jsx index a350992..51346af 100644 --- a/frontend/src/IPRangesManager.jsx +++ b/frontend/src/IPRangesManager.jsx @@ -31,6 +31,7 @@ import ErrorAlert from './components/ErrorAlert.jsx'; import { notifyMutationSuccess } from './components/NotifyProvider.jsx'; import ImportModal from './components/ImportModal.jsx'; import QuickAddBar from './components/QuickAddBar.jsx'; +import AccordionCard from './components/AccordionCard.jsx'; const API_URL = '/api'; @@ -779,24 +780,34 @@ function IPRangesManager() { - {/* QuickAdd stays for batch input */} - { const [cidr, c] = String(line).split(/\s+/); return { ipRange: (cidr||'').trim(), community: (c||'').trim() }; }} - validateItem={(obj) => isValidCidr(obj.ipRange) && isValidCommunity(obj.community)} - onApply={(list) => { - setItems(prev => { - const merged = [...prev, ...list]; - const map = new Map(); - for (const it of merged) { - const key = String(it.ipRange).trim(); - if (!map.has(key)) map.set(key, { ipRange: key, community: String(it.community).trim() }); - } - return Array.from(map.values()); - }); - }} - /> + {/* Дополнительные варианты */} + + { const [cidr, c] = String(line).split(/\s+/); return { ipRange: (cidr||'').trim(), community: (c||'').trim() }; }} + validateItem={(obj) => isValidCidr(obj.ipRange) && isValidCommunity(obj.community)} + onApply={(list) => { + setItems(prev => { + const merged = [...prev, ...list]; + const map = new Map(); + for (const it of merged) { + const key = String(it.ipRange).trim(); + if (!map.has(key)) map.set(key, { ipRange: key, community: String(it.community).trim() }); + } + return Array.from(map.values()); + }); + }} + /> +
{ e.preventDefault(); }} + onDrop={onDropImport} + > +
+ Перетащите файл TXT/CSV сюда для импорта (формат: CIDR community) +
+
+
{/* Drag & Drop импорт */}
+
setOpen(v => !v)} aria-expanded={open}> +

{title}

+ +
+ {open && ( +
+ {children} +
+ )} +
+ ); +} + +export default AccordionCard; + + diff --git a/frontend/src/components/PageHeader.jsx b/frontend/src/components/PageHeader.jsx index abd2523..8d2b756 100644 --- a/frontend/src/components/PageHeader.jsx +++ b/frontend/src/components/PageHeader.jsx @@ -17,7 +17,7 @@ function PageHeader({ title, pretitle, actions, meta }) { {/* Отдельная строка под заголовком: действия страницы */} {actions && ( -
+
{actions}
)}