'use client'; import { useState, useEffect } from 'react'; import { Globe, Plus, Edit, Trash2, RefreshCw, Check, X, Search, Filter, Download, Upload, Trash } from 'lucide-react'; const DNSManager = () => { const [domains, setDomains] = useState([]); const [selectedDomain, setSelectedDomain] = useState(''); const [records, setRecords] = useState([]); const [filteredRecords, setFilteredRecords] = useState([]); const [loading, setLoading] = useState(false); const [showAddRecord, setShowAddRecord] = useState(false); const [editingRecord, setEditingRecord] = useState(null); const [selectedRecords, setSelectedRecords] = useState(new Set()); const [searchTerm, setSearchTerm] = useState(''); const [filterType, setFilterType] = useState('all'); const [newRecord, setNewRecord] = useState({ fieldType: 'A', subDomain: '', target: '', ttl: 3600 }); const [bulkUpdate, setBulkUpdate] = useState({ show: false, target: '', type: 'A' }); const [showImport, setShowImport] = useState(false); const [importContent, setImportContent] = useState(''); const [replaceAll, setReplaceAll] = useState(false); const [importResult, setImportResult] = useState(null); const fetchDomains = async () => { try { const response = await fetch('/api/domains'); const data = await response.json(); if (data.success && data.domains) { const domainList = data.domains.map(d => typeof d === 'string' ? d : d.domain); setDomains(domainList); if (domainList.length > 0 && !selectedDomain) { setSelectedDomain(domainList[0]); } } } catch (error) { console.error('Error fetching domains:', error); } }; const fetchRecords = async () => { if (!selectedDomain) return; setLoading(true); try { const response = await fetch(`/api/domains/${selectedDomain}/records`); const data = await response.json(); if (data.success) { setRecords(data.records || []); } } catch (error) { console.error('Error fetching records:', error); } setLoading(false); setSelectedRecords(new Set()); }; useEffect(() => { fetchDomains(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (selectedDomain) { fetchRecords(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedDomain]); useEffect(() => { let filtered = records; if (filterType !== 'all') { filtered = filtered.filter(r => r.fieldType === filterType); } if (searchTerm) { filtered = filtered.filter(r => r.subDomain?.toLowerCase().includes(searchTerm.toLowerCase()) || r.target?.toLowerCase().includes(searchTerm.toLowerCase()) ); } setFilteredRecords(filtered); }, [records, searchTerm, filterType]); const handleAddRecord = async () => { try { const response = await fetch(`/api/domains/${selectedDomain}/records`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newRecord) }); if (response.ok) { setShowAddRecord(false); setNewRecord({ fieldType: 'A', subDomain: '', target: '', ttl: 3600 }); fetchRecords(); } } catch (error) { console.error('Error adding record:', error); } }; const handleUpdateRecord = async () => { try { const response = await fetch(`/api/domains/${selectedDomain}/records`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(editingRecord) }); if (response.ok) { setEditingRecord(null); fetchRecords(); } } catch (error) { console.error('Error updating record:', error); } }; const handleDeleteRecord = async (recordId) => { if (!confirm('Are you sure you want to delete this record?')) return; try { const response = await fetch(`/api/domains/${selectedDomain}/records?recordId=${recordId}`, { method: 'DELETE' }); if (response.ok) { fetchRecords(); } } catch (error) { console.error('Error deleting record:', error); } }; const handleBulkUpdate = async () => { if (selectedRecords.size === 0) return; try { const response = await fetch(`/api/domains/${selectedDomain}/bulk-update`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain: selectedDomain, recordIds: Array.from(selectedRecords), target: bulkUpdate.target, fieldType: bulkUpdate.type }) }); const data = await response.json(); if (data.success) { setBulkUpdate({ show: false, target: '', type: 'A' }); setSelectedRecords(new Set()); fetchRecords(); } } catch (error) { console.error('Error bulk updating records:', error); } }; const handleBulkDelete = async () => { if (selectedRecords.size === 0) return; if (!confirm(`¿Está seguro de que desea eliminar ${selectedRecords.size} registro(s)?`)) { return; } try { const response = await fetch(`/api/domains/${selectedDomain}/bulk-delete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ recordIds: Array.from(selectedRecords) }) }); const data = await response.json(); if (data.success) { setSelectedRecords(new Set()); fetchRecords(); } } catch (error) { console.error('Error bulk deleting records:', error); } }; const handleExport = async () => { if (!selectedDomain) return; try { const response = await fetch(`/api/domains/${selectedDomain}/export`); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${selectedDomain}.zone`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } } catch (error) { console.error('Error exporting zone:', error); } }; const handleImport = async () => { if (!importContent.trim()) { alert('Por favor, ingrese el contenido de la zona BIND9'); return; } try { const response = await fetch(`/api/domains/${selectedDomain}/import`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ zoneContent: importContent, replaceAll: replaceAll }) }); const data = await response.json(); if (data.success) { setImportResult(data); setTimeout(() => { setShowImport(false); setImportContent(''); setReplaceAll(false); setImportResult(null); fetchRecords(); }, 3000); } } catch (error) { console.error('Error importing zone:', error); } }; const handleFileImport = (e) => { const file = e.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (event) => { setImportContent(event.target?.result || ''); }; reader.readAsText(file); } }; const toggleRecordSelection = (recordId) => { const newSelection = new Set(selectedRecords); if (newSelection.has(recordId)) { newSelection.delete(recordId); } else { newSelection.add(recordId); } setSelectedRecords(newSelection); }; const selectAllFiltered = () => { if (selectedRecords.size === filteredRecords.length) { setSelectedRecords(new Set()); } else { setSelectedRecords(new Set(filteredRecords.map(r => r.id))); } }; const refreshDNSZone = async () => { if (!selectedDomain) return; setLoading(true); try { const response = await fetch('/api/dns/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain: selectedDomain }) }); const data = await response.json(); if (data.success) { await fetchRecords(); } } catch (error) { console.error('Error refreshing DNS zone:', error); } setLoading(false); }; const getRecordTypeColor = (type) => { const colors = { 'A': 'bg-blue-500 text-white', 'AAAA': 'bg-purple-500 text-white', 'CNAME': 'bg-green-500 text-white', 'MX': 'bg-orange-500 text-white', 'TXT': 'bg-gray-500 text-white', 'SRV': 'bg-pink-500 text-white', 'NS': 'bg-yellow-500 text-white' }; return colors[type] || 'bg-gray-500 text-white'; }; return (
Manage your domain DNS records
Loading records...
| 0} onChange={selectAllFiltered} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" /> | Tipo | Nombre | Valor | TTL | Acciones |
|---|---|---|---|---|---|
| toggleRecordSelection(record.id)} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" /> | {record.fieldType} | {record.subDomain || '@'} | {record.target} | {record.ttl} |
No se encontraron registros DNS
Update {selectedRecords.size} selected record(s)
Total: {importResult.summary.total} | Exitosos: {importResult.summary.success} | Fallidos: {importResult.summary.failed}
⚠️ Advertencia: Esta acción eliminará todos los registros existentes antes de importar.
)}