refactor(Managers): replace modal implementation with FormModal for community editing in ASNs, Domains, and IPRanges managers to enhance code maintainability and user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 54s

This commit is contained in:
2026-02-16 18:07:48 +07:00
parent 59082aa0d0
commit 1c953ed9d8
3 changed files with 102 additions and 147 deletions
+34 -49
View File
@@ -40,6 +40,7 @@ import BulkActionsBar from './components/BulkActionsBar.jsx';
import Tooltip from './components/Tooltip.jsx'; import Tooltip from './components/Tooltip.jsx';
import Pagination from './components/Pagination.jsx'; import Pagination from './components/Pagination.jsx';
import AddItemModal from './components/AddItemModal.jsx'; import AddItemModal from './components/AddItemModal.jsx';
import FormModal from './components/FormModal.jsx';
import { getAsnName, getAsnNameSync } from './lib/asn.js'; import { getAsnName, getAsnNameSync } from './lib/asn.js';
import LastSaved from './components/LastSaved.jsx'; import LastSaved from './components/LastSaved.jsx';
@@ -847,57 +848,41 @@ function ASNsNewManager() {
placeholder={'12345 65000:100'} placeholder={'12345 65000:100'}
/> />
{/* Модальное окно редактирования community */} {/* Модальное окно редактирования community */}
{editModalOpen && itemBeingEdited && ( <FormModal
<div className="modal modal-blur fade show" style={{ display: 'block' }} tabIndex="-1"> show={editModalOpen && !!itemBeingEdited}
<div className="modal-dialog modal-dialog-centered" role="document"> onClose={handleCancelEdit}
<div className="modal-content"> onSubmit={handleSaveEdit}
<button title="Редактировать community"
type="button" submitLabel="Сохранить"
className="btn-close" submitIcon={IconCheck}
onClick={handleCancelEdit} size="md"
aria-label="Закрыть" centered
></button> disabled={!isValidCommunity(editingValue)}
<div className="modal-header"> >
<h3 className="modal-title">Редактировать community</h3> {itemBeingEdited && (
</div> <>
<div className="modal-body"> <p className="text-muted mb-2">
<p className="text-muted mb-2"> ASN: <span className="font-monospace">{itemBeingEdited.asn}</span>
ASN: <span className="font-monospace">{itemBeingEdited.asn}</span> </p>
</p> <div className="mb-3">
<div className="mb-3"> <label className="form-label">Community</label>
<label className="form-label">Community</label> <CommunityAutocompleteInput
<CommunityAutocompleteInput value={editingValue}
value={editingValue} onChange={setEditingValue}
onChange={setEditingValue} communities={communities}
communities={communities} onKeyDown={handleEditKeyDown}
onKeyDown={handleEditKeyDown} className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`}
className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} useShortValue={true}
useShortValue={true} />
/> {!isValidCommunity(editingValue) && (
{!isValidCommunity(editingValue) && ( <div className="invalid-feedback d-block">
<div className="invalid-feedback d-block"> Введите корректное значение community (число или N:N).
Введите корректное значение community (число или N:N).
</div>
)}
</div> </div>
</div> )}
<div className="modal-footer">
<button className="btn" onClick={handleCancelEdit}>
Отмена
</button>
<button
className="btn btn-primary"
onClick={handleSaveEdit}
disabled={!isValidCommunity(editingValue)}
>
<IconCheck className="icon me-1" size={18} />
Сохранить
</button>
</div>
</div> </div>
</div> </>
</div> )}
)} </FormModal>
<HistoryModal <HistoryModal
resource="asns" resource="asns"
show={historyOpen} show={historyOpen}
+34 -49
View File
@@ -47,6 +47,7 @@ import Tooltip from './components/Tooltip.jsx';
import Pagination from './components/Pagination.jsx'; import Pagination from './components/Pagination.jsx';
import AddItemModal from './components/AddItemModal.jsx'; import AddItemModal from './components/AddItemModal.jsx';
import LastSaved from './components/LastSaved.jsx'; import LastSaved from './components/LastSaved.jsx';
import FormModal from './components/FormModal.jsx';
import { useToast } from './components/ToastContainer.jsx'; import { useToast } from './components/ToastContainer.jsx';
const API_URL = '/api'; const API_URL = '/api';
@@ -870,57 +871,41 @@ function DomainsNewManager() {
onClose={() => setWsOpen(false)} onClose={() => setWsOpen(false)}
/> />
{/* Модальное окно редактирования community */} {/* Модальное окно редактирования community */}
{editModalOpen && itemBeingEdited && ( <FormModal
<div className="modal modal-blur fade show" style={{ display: 'block' }} tabIndex="-1"> show={editModalOpen && !!itemBeingEdited}
<div className="modal-dialog modal-dialog-centered" role="document"> onClose={handleCancelEdit}
<div className="modal-content"> onSubmit={handleSaveEdit}
<button title="Редактировать community"
type="button" submitLabel="Сохранить"
className="btn-close" submitIcon={IconCheck}
onClick={handleCancelEdit} size="md"
aria-label="Закрыть" centered
></button> disabled={!isValidCommunity(editingValue)}
<div className="modal-header"> >
<h3 className="modal-title">Редактировать community</h3> {itemBeingEdited && (
</div> <>
<div className="modal-body"> <p className="text-muted mb-2">
<p className="text-muted mb-2"> Домен: <span className="font-monospace">{itemBeingEdited.domain}</span>
Домен: <span className="font-monospace">{itemBeingEdited.domain}</span> </p>
</p> <div className="mb-3">
<div className="mb-3"> <label className="form-label">Community</label>
<label className="form-label">Community</label> <CommunityAutocompleteInput
<CommunityAutocompleteInput value={editingValue}
value={editingValue} onChange={setEditingValue}
onChange={setEditingValue} communities={communities}
communities={communities} onKeyDown={handleEditKeyDown}
onKeyDown={handleEditKeyDown} className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`}
className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} useShortValue={true}
useShortValue={true} />
/> {!isValidCommunity(editingValue) && (
{!isValidCommunity(editingValue) && ( <div className="invalid-feedback d-block">
<div className="invalid-feedback d-block"> Введите корректное значение community (число или N:N).
Введите корректное значение community (число или N:N).
</div>
)}
</div> </div>
</div> )}
<div className="modal-footer">
<button className="btn" onClick={handleCancelEdit}>
Отмена
</button>
<button
className="btn btn-primary"
onClick={handleSaveEdit}
disabled={!isValidCommunity(editingValue)}
>
<IconCheck className="icon me-1" size={18} />
Сохранить
</button>
</div>
</div> </div>
</div> </>
</div> )}
)} </FormModal>
<ConfirmModal <ConfirmModal
show={clearCommunitiesOpen} show={clearCommunitiesOpen}
onClose={() => setClearCommunitiesOpen(false)} onClose={() => setClearCommunitiesOpen(false)}
+34 -49
View File
@@ -43,6 +43,7 @@ import Tooltip from './components/Tooltip.jsx';
import Pagination from './components/Pagination.jsx'; import Pagination from './components/Pagination.jsx';
import AddItemModal from './components/AddItemModal.jsx'; import AddItemModal from './components/AddItemModal.jsx';
import LastSaved from './components/LastSaved.jsx'; import LastSaved from './components/LastSaved.jsx';
import FormModal from './components/FormModal.jsx';
const API_URL = '/api'; const API_URL = '/api';
@@ -1084,57 +1085,41 @@ function IPRangesManager() {
placeholder={'192.168.1.0/24 65000:100'} placeholder={'192.168.1.0/24 65000:100'}
/> />
{/* Модальное окно редактирования community */} {/* Модальное окно редактирования community */}
{editModalOpen && itemBeingEdited && ( <FormModal
<div className="modal modal-blur fade show" style={{ display: 'block' }} tabIndex="-1"> show={editModalOpen && !!itemBeingEdited}
<div className="modal-dialog modal-dialog-centered" role="document"> onClose={handleCancelEdit}
<div className="modal-content"> onSubmit={handleSaveEdit}
<button title="Редактировать community"
type="button" submitLabel="Сохранить"
className="btn-close" submitIcon={IconCheck}
onClick={handleCancelEdit} size="md"
aria-label="Закрыть" centered
></button> disabled={!isValidCommunity(editingValue)}
<div className="modal-header"> >
<h3 className="modal-title">Редактировать community</h3> {itemBeingEdited && (
</div> <>
<div className="modal-body"> <p className="text-muted mb-2">
<p className="text-muted mb-2"> IP-диапазон: <span className="font-monospace">{itemBeingEdited.ipRange}</span>
IP-диапазон: <span className="font-monospace">{itemBeingEdited.ipRange}</span> </p>
</p> <div className="mb-3">
<div className="mb-3"> <label className="form-label">Community</label>
<label className="form-label">Community</label> <CommunityAutocompleteInput
<CommunityAutocompleteInput value={editingValue}
value={editingValue} onChange={setEditingValue}
onChange={setEditingValue} communities={communities}
communities={communities} onKeyDown={handleEditKeyDown}
onKeyDown={handleEditKeyDown} className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`}
className={`form-control${isValidCommunity(editingValue) ? '' : ' is-invalid'}`} useShortValue={true}
useShortValue={true} />
/> {!isValidCommunity(editingValue) && (
{!isValidCommunity(editingValue) && ( <div className="invalid-feedback d-block">
<div className="invalid-feedback d-block"> Введите корректное значение community (число или N:N).
Введите корректное значение community (число или N:N).
</div>
)}
</div> </div>
</div> )}
<div className="modal-footer">
<button className="btn" onClick={handleCancelEdit}>
Отмена
</button>
<button
className="btn btn-primary"
onClick={handleSaveEdit}
disabled={!isValidCommunity(editingValue)}
>
<IconCheck className="icon me-1" size={18} />
Сохранить
</button>
</div>
</div> </div>
</div> </>
</div> )}
)} </FormModal>
<HistoryModal <HistoryModal
resource="ip-ranges" resource="ip-ranges"
show={historyOpen} show={historyOpen}