Replace window.confirm() with themed ConfirmModal across dashboard
This commit is contained in:
@@ -8,6 +8,7 @@ import AuditLog from './components/AuditLog';
|
||||
import NvdSyncModal from './components/NvdSyncModal';
|
||||
import NavDrawer from './components/NavDrawer';
|
||||
import CalendarWidget from './components/CalendarWidget';
|
||||
import ConfirmModal from './components/ConfirmModal';
|
||||
import VulnerabilityTriagePage from './components/pages/ReportingPage';
|
||||
import KnowledgeBasePage from './components/pages/KnowledgeBasePage';
|
||||
import ExportsPage from './components/pages/ExportsPage';
|
||||
@@ -241,6 +242,9 @@ export default function App() {
|
||||
const [archiveList, setArchiveList] = useState([]);
|
||||
const [archiveListLoading, setArchiveListLoading] = useState(false);
|
||||
|
||||
// Confirmation modal state — replaces window.confirm()
|
||||
const [pendingConfirm, setPendingConfirm] = useState(null);
|
||||
|
||||
const toggleCVEExpand = (cveId) => {
|
||||
setExpandedCVEs(prev => ({ ...prev, [cveId]: !prev[cveId] }));
|
||||
};
|
||||
@@ -532,26 +536,30 @@ export default function App() {
|
||||
};
|
||||
|
||||
const handleDeleteDocument = async (docId, cveId, vendor) => {
|
||||
if (!window.confirm('Are you sure you want to delete this document?')) {
|
||||
return;
|
||||
}
|
||||
setPendingConfirm({
|
||||
title: 'Delete Document',
|
||||
message: 'Are you sure you want to delete this document?',
|
||||
confirmText: 'Delete',
|
||||
onConfirm: async () => {
|
||||
setPendingConfirm(null);
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/documents/${docId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/documents/${docId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to delete document');
|
||||
|
||||
if (!response.ok) throw new Error('Failed to delete document');
|
||||
|
||||
alert('Document deleted successfully!');
|
||||
const key = `${cveId}-${vendor}`;
|
||||
delete cveDocuments[key];
|
||||
await fetchDocuments(cveId, vendor);
|
||||
fetchCVEs();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
alert('Document deleted successfully!');
|
||||
const key = `${cveId}-${vendor}`;
|
||||
delete cveDocuments[key];
|
||||
await fetchDocuments(cveId, vendor);
|
||||
fetchCVEs();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleEditCVE = (cve) => {
|
||||
@@ -644,65 +652,73 @@ export default function App() {
|
||||
};
|
||||
|
||||
const handleDeleteCVEEntry = async (cve) => {
|
||||
if (!window.confirm(`Are you sure you want to delete the "${cve.vendor}" entry for ${cve.cve_id}? This will also delete all associated documents.`)) {
|
||||
return;
|
||||
}
|
||||
setPendingConfirm({
|
||||
title: 'Delete Vendor Entry',
|
||||
message: `Are you sure you want to delete the "${cve.vendor}" entry for ${cve.cve_id}? This will also delete all associated documents.`,
|
||||
confirmText: 'Delete',
|
||||
onConfirm: async () => {
|
||||
setPendingConfirm(null);
|
||||
try {
|
||||
const url = `${API_BASE}/cves/${cve.id}`;
|
||||
console.log('DELETE request to:', url);
|
||||
const response = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
try {
|
||||
const url = `${API_BASE}/cves/${cve.id}`;
|
||||
console.log('DELETE request to:', url);
|
||||
const response = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) {
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
throw new Error(data.error || 'Failed to delete CVE entry');
|
||||
} else {
|
||||
throw new Error(`Server returned ${response.status} ${response.statusText}. Check API_BASE configuration.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
throw new Error(data.error || 'Failed to delete CVE entry');
|
||||
} else {
|
||||
throw new Error(`Server returned ${response.status} ${response.statusText}. Check API_BASE configuration.`);
|
||||
alert(`Deleted ${cve.vendor} entry for ${cve.cve_id}`);
|
||||
fetchCVEs();
|
||||
fetchVendors();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
alert(`Deleted ${cve.vendor} entry for ${cve.cve_id}`);
|
||||
fetchCVEs();
|
||||
fetchVendors();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteEntireCVE = async (cveId, vendorCount) => {
|
||||
if (!window.confirm(`Are you sure you want to delete ALL ${vendorCount} vendor entries for ${cveId}? This will permanently remove all associated documents and files.`)) {
|
||||
return;
|
||||
}
|
||||
setPendingConfirm({
|
||||
title: 'Delete Entire CVE',
|
||||
message: `Are you sure you want to delete ALL ${vendorCount} vendor entries for ${cveId}? This will permanently remove all associated documents and files.`,
|
||||
confirmText: 'Delete All',
|
||||
onConfirm: async () => {
|
||||
setPendingConfirm(null);
|
||||
try {
|
||||
const url = `${API_BASE}/cves/by-cve-id/${encodeURIComponent(cveId)}`;
|
||||
console.log('DELETE request to:', url);
|
||||
const response = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
try {
|
||||
const url = `${API_BASE}/cves/by-cve-id/${encodeURIComponent(cveId)}`;
|
||||
console.log('DELETE request to:', url);
|
||||
const response = await fetch(url, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) {
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
throw new Error(data.error || 'Failed to delete CVE');
|
||||
} else {
|
||||
throw new Error(`Server returned ${response.status} ${response.statusText}. Check API_BASE configuration.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
throw new Error(data.error || 'Failed to delete CVE');
|
||||
} else {
|
||||
throw new Error(`Server returned ${response.status} ${response.statusText}. Check API_BASE configuration.`);
|
||||
alert(`Deleted all entries for ${cveId}`);
|
||||
fetchCVEs();
|
||||
fetchVendors();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
alert(`Deleted all entries for ${cveId}`);
|
||||
fetchCVEs();
|
||||
fetchVendors();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddTicket = async (e) => {
|
||||
@@ -770,18 +786,25 @@ export default function App() {
|
||||
};
|
||||
|
||||
const handleDeleteTicket = async (ticket) => {
|
||||
if (!window.confirm(`Delete ticket ${ticket.ticket_key}?`)) return;
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/jira-tickets/${ticket.id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to delete ticket');
|
||||
alert('Ticket deleted');
|
||||
fetchJiraTickets();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
setPendingConfirm({
|
||||
title: 'Delete Ticket',
|
||||
message: `Delete ticket ${ticket.ticket_key}?`,
|
||||
confirmText: 'Delete',
|
||||
onConfirm: async () => {
|
||||
setPendingConfirm(null);
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/jira-tickets/${ticket.id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to delete ticket');
|
||||
alert('Ticket deleted');
|
||||
fetchJiraTickets();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const openAddTicketForCVE = (cve_id, vendor) => {
|
||||
@@ -855,18 +878,25 @@ export default function App() {
|
||||
};
|
||||
|
||||
const handleDeleteArcherTicket = async (ticket) => {
|
||||
if (!window.confirm(`Delete Archer ticket ${ticket.exc_number}?`)) return;
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/archer-tickets/${ticket.id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to delete Archer ticket');
|
||||
alert('Archer ticket deleted');
|
||||
fetchArcherTickets();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
setPendingConfirm({
|
||||
title: 'Delete Archer Ticket',
|
||||
message: `Delete Archer ticket ${ticket.exc_number}?`,
|
||||
confirmText: 'Delete',
|
||||
onConfirm: async () => {
|
||||
setPendingConfirm(null);
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/archer-tickets/${ticket.id}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to delete Archer ticket');
|
||||
alert('Archer ticket deleted');
|
||||
fetchArcherTickets();
|
||||
} catch (err) {
|
||||
alert(`Error: ${err.message}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const openAddArcherTicketForCVE = (cve_id, vendor) => {
|
||||
@@ -2420,6 +2450,17 @@ export default function App() {
|
||||
|
||||
</div>}
|
||||
{/* End Three Column Layout */}
|
||||
|
||||
{/* Confirmation Modal */}
|
||||
<ConfirmModal
|
||||
open={!!pendingConfirm}
|
||||
title={pendingConfirm?.title}
|
||||
message={pendingConfirm?.message}
|
||||
confirmText={pendingConfirm?.confirmText}
|
||||
variant={pendingConfirm?.variant || 'danger'}
|
||||
onConfirm={pendingConfirm?.onConfirm}
|
||||
onCancel={() => setPendingConfirm(null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user