From 6efe497e184778d24ead7ed4ca8140aaf1d345d4 Mon Sep 17 00:00:00 2001 From: shats Date: Mon, 16 Feb 2026 17:55:32 +0700 Subject: [PATCH] refactor(Managers): implement modal editing for community fields in ASNs, Domains, and IPRanges managers to enhance user experience and streamline editing process --- frontend/src/ASNsNewManager.jsx | 137 ++++++++++++++---------- frontend/src/DomainsNewManager.jsx | 166 ++++++++++++++++------------- frontend/src/IPRangesManager.jsx | 136 ++++++++++++++--------- 3 files changed, 259 insertions(+), 180 deletions(-) diff --git a/frontend/src/ASNsNewManager.jsx b/frontend/src/ASNsNewManager.jsx index 005585d..b740ef6 100644 --- a/frontend/src/ASNsNewManager.jsx +++ b/frontend/src/ASNsNewManager.jsx @@ -58,8 +58,9 @@ function ASNsNewManager() { const [searchTerm, setSearchTerm] = useState(''); const searchTimer = useRef(null); const didInit = useRef(false); - const [editingAsn, setEditingAsn] = useState(null); const [editingValue, setEditingValue] = useState(''); + const [editModalOpen, setEditModalOpen] = useState(false); + const [itemBeingEdited, setItemBeingEdited] = useState(null); const [loading, setLoading] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); @@ -69,7 +70,6 @@ function ASNsNewManager() { const [sortField, setSortField] = useState('asn'); const [sortOrder, setSortOrder] = useState('asc'); const [filterCommunity, setFilterCommunity] = useState(''); - const editInputRef = useRef(null); const pageSize = 10; const [asnNameMap, setAsnNameMap] = useState({}); const [selectedItems, setSelectedItems] = useState(new Set()); @@ -152,24 +152,28 @@ function ASNsNewManager() { }; const handleEdit = (item) => { - setEditingAsn(item.asn); + setItemBeingEdited(item); setEditingValue(item.community); + setEditModalOpen(true); }; - const handleSaveEdit = (asn) => { + const handleSaveEdit = () => { + if (!itemBeingEdited) return; if (!isValidCommunity(editingValue)) { setError('Community должен быть числом.'); return; } const updatedItems = items.map(i => - i.asn === asn ? { ...i, community: String(editingValue).trim() } : i + i.asn === itemBeingEdited.asn ? { ...i, community: String(editingValue).trim() } : i ); setItems(updatedItems); - setEditingAsn(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleCancelEdit = () => { - setEditingAsn(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleDeleteItem = (asnToDelete) => { @@ -477,13 +481,6 @@ function ASNsNewManager() { } }; - // Улучшенный инлайн-редакт - useEffect(() => { - if (editingAsn && editInputRef.current) { - editInputRef.current.focus(); - } - }, [editingAsn]); - // Глобальные хоткеи: Ctrl+S — сохранить изменения useEffect(() => { const onKey = (e) => { @@ -496,9 +493,15 @@ function ASNsNewManager() { return () => window.removeEventListener('keydown', onKey); }, [loading, items, originalItems, etag, sortField, sortOrder, filterCommunity]); - const handleEditKeyDown = (e, asn) => { - if (e.key === 'Enter') handleSaveEdit(asn); - if (e.key === 'Escape') handleCancelEdit(); + const handleEditKeyDown = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleSaveEdit(); + } + if (e.key === 'Escape') { + e.preventDefault(); + handleCancelEdit(); + } }; return ( @@ -734,7 +737,7 @@ function ASNsNewManager() { {paginatedItems.map((item, idx) => ( - + {renderCommunityBadge(item.community)}
- {editingAsn === item.asn ? ( - <> - handleEditKeyDown(e, item.asn)} - className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} - style={{ width: '150px' }} - useShortValue={true} - /> - - - - - - - - ) : ( - <> - - - - - - - - )} + + + + + +
@@ -856,6 +833,58 @@ function ASNsNewManager() { sampleHeader={['asn','community']} placeholder={'12345 65000:100'} /> + {/* Модальное окно редактирования community */} + {editModalOpen && itemBeingEdited && ( +
+
+
+ +
+

Редактировать community

+
+
+

+ ASN: {itemBeingEdited.asn} +

+
+ + + {!isValidCommunity(editingValue) && ( +
+ Введите корректное значение community (число или N:N). +
+ )} +
+
+
+ + +
+
+
+
+ )} { - setEditingDomain(item.domain); + setItemBeingEdited(item); setEditingValue(item.community); + setEditModalOpen(true); }; - const handleSaveEdit = (domainName) => { + const handleSaveEdit = () => { + if (!itemBeingEdited) return; if (!isValidCommunity(editingValue)) { setError('Community должен быть числом.'); return; } const updatedItems = items.map(i => - i.domain === domainName ? { ...i, community: String(editingValue).trim() } : i + i.domain === itemBeingEdited.domain ? { ...i, community: String(editingValue).trim() } : i ); setItems(updatedItems); - setEditingDomain(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleCancelEdit = () => { - setEditingDomain(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleDeleteItem = (domainNameToDelete) => { @@ -426,13 +430,6 @@ function DomainsNewManager() { } }; - // Улучшенный инлайн-редакт - useEffect(() => { - if (editingDomain && editInputRef.current) { - editInputRef.current.focus(); - } - }, [editingDomain]); - // Глобальные хоткеи: Ctrl+S — сохранить изменения useEffect(() => { const onKey = (e) => { @@ -445,9 +442,15 @@ function DomainsNewManager() { return () => window.removeEventListener('keydown', onKey); }, [loading, items, originalItems, etag, sortField, sortOrder, filterCommunity]); - const handleEditKeyDown = (e, domainName) => { - if (e.key === 'Enter') handleSaveEdit(domainName); - if (e.key === 'Escape') handleCancelEdit(); + const handleEditKeyDown = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleSaveEdit(); + } + if (e.key === 'Escape') { + e.preventDefault(); + handleCancelEdit(); + } }; // Bulk operations handlers @@ -734,7 +737,7 @@ function DomainsNewManager() { {paginatedItems.map((item, idx) => (
- {editingDomain === item.domain ? ( - <> - handleEditKeyDown(e, item.domain)} - className={`form-control d-inline-block me-2${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} - style={{ width: '150px' }} - useShortValue={true} - /> - - - - - - - - ) : ( - <> - - - - - - - - )} + + + + + +
@@ -895,6 +863,58 @@ function DomainsNewManager() { url={wsUrl} onClose={() => setWsOpen(false)} /> + {/* Модальное окно редактирования community */} + {editModalOpen && itemBeingEdited && ( +
+
+
+ +
+

Редактировать community

+
+
+

+ Домен: {itemBeingEdited.domain} +

+
+ + + {!isValidCommunity(editingValue) && ( +
+ Введите корректное значение community (число или N:N). +
+ )} +
+
+
+ + +
+
+
+
+ )} setClearCommunitiesOpen(false)} diff --git a/frontend/src/IPRangesManager.jsx b/frontend/src/IPRangesManager.jsx index ad09223..5573298 100644 --- a/frontend/src/IPRangesManager.jsx +++ b/frontend/src/IPRangesManager.jsx @@ -59,8 +59,9 @@ function IPRangesManager() { const [searchTerm, setSearchTerm] = useState(''); const searchTimer = useRef(null); const didInit = useRef(false); - const [editingIp, setEditingIp] = useState(null); const [editingValue, setEditingValue] = useState(''); + const [editModalOpen, setEditModalOpen] = useState(false); + const [itemBeingEdited, setItemBeingEdited] = useState(null); const [loading, setLoading] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); @@ -70,7 +71,6 @@ function IPRangesManager() { const [sortField, setSortField] = useState('ipRange'); const [sortOrder, setSortOrder] = useState('asc'); const [filterCommunity, setFilterCommunity] = useState(''); - const editInputRef = useRef(null); const pageSize = 10; const [selectedItems, setSelectedItems] = useState(new Set()); @@ -162,24 +162,28 @@ function IPRangesManager() { }; const handleEdit = (item) => { - setEditingIp(item.ipRange); + setItemBeingEdited(item); setEditingValue(item.community); + setEditModalOpen(true); }; - const handleSaveEdit = (ipRange) => { + const handleSaveEdit = () => { + if (!itemBeingEdited) return; if (!isValidCommunity(editingValue)) { setError('Community должен быть числом.'); return; } const updatedItems = items.map(i => - i.ipRange === ipRange ? { ...i, community: String(editingValue).trim() } : i + i.ipRange === itemBeingEdited.ipRange ? { ...i, community: String(editingValue).trim() } : i ); setItems(updatedItems); - setEditingIp(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleCancelEdit = () => { - setEditingIp(null); + setEditModalOpen(false); + setItemBeingEdited(null); }; const handleDeleteItem = (ipRangeToDelete) => { @@ -499,12 +503,6 @@ function IPRangesManager() { } }; - // Улучшенный инлайн-редакт - useEffect(() => { - if (editingIp && editInputRef.current) { - editInputRef.current.focus(); - } - }, [editingIp]); // Глобальные хоткеи: Ctrl+S — сохранить изменения useEffect(() => { const onKey = (e) => { @@ -517,9 +515,15 @@ function IPRangesManager() { return () => window.removeEventListener('keydown', onKey); }, [loading, items, originalItems, etag, sortField, sortOrder, filterCommunity]); - const handleEditKeyDown = (e, ipRange) => { - if (e.key === 'Enter') handleSaveEdit(ipRange); - if (e.key === 'Escape') handleCancelEdit(); + const handleEditKeyDown = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleSaveEdit(); + } + if (e.key === 'Escape') { + e.preventDefault(); + handleCancelEdit(); + } }; // ===== Аналитика: утилиты ===== @@ -977,7 +981,7 @@ function IPRangesManager() { {paginatedItems.map((item, idx) => ( - + {renderCommunityBadge(item.community)}
- {editingIp === item.ipRange ? ( - <> - handleEditKeyDown(e, item.ipRange)} - useShortValue={true} - /> - - - - - - - - ) : ( - <> - - - - - - - - )} + + + + + +
@@ -1092,6 +1070,58 @@ function IPRangesManager() { sampleHeader={['ipRange','community']} placeholder={'192.168.1.0/24 65000:100'} /> + {/* Модальное окно редактирования community */} + {editModalOpen && itemBeingEdited && ( +
+
+
+ +
+

Редактировать community

+
+
+

+ IP-диапазон: {itemBeingEdited.ipRange} +

+
+ + + {!isValidCommunity(editingValue) && ( +
+ Введите корректное значение community (число или N:N). +
+ )} +
+
+
+ + +
+
+
+
+ )}