feat: add node deletion confirmation modal and global sequence guard for dashboard

This commit is contained in:
mik-tf
2025-09-08 23:06:58 -04:00
parent 5f850dd8f2
commit 138f67e02e
3 changed files with 166 additions and 4 deletions

View File

@@ -4092,7 +4092,9 @@ async function loadExistingGroups() {
}
// Stale-guard for node details fetches
let __nodeDetailsSeq = 0;
// Guard against redeclaration - use window scope to persist across reloads
window.__nodeDetailsSeq = window.__nodeDetailsSeq || 0;
let __nodeDetailsSeq = window.__nodeDetailsSeq;
/**
* View node details
@@ -4105,7 +4107,7 @@ async function loadExistingGroups() {
window.__nodeDetailsController = (typeof AbortController !== 'undefined') ? new AbortController() : null;
// Sequence guard to avoid race conditions
const requestId = ++__nodeDetailsSeq;
const requestId = ++window.__nodeDetailsSeq;
const nodeData = await window.apiJson(`/api/dashboard/farm-nodes/${nodeId}`, {
cache: 'no-store',
@@ -4113,7 +4115,7 @@ async function loadExistingGroups() {
});
// If a newer request started, ignore this response
if (requestId !== __nodeDetailsSeq) return;
if (requestId !== window.__nodeDetailsSeq) return;
console.log('👁️ Loaded node details:', nodeData);
showNodeDetailsModal(nodeData);
@@ -4123,6 +4125,47 @@ async function loadExistingGroups() {
}
}
/**
* Delete node configuration (show confirmation modal)
*/
async function deleteNodeConfiguration(nodeId) {
console.log('🗑️ Initiating node deletion for nodeId:', nodeId);
if (!nodeId) {
console.error('🗑️ No node ID provided for deletion');
showNotification('Error: No node ID provided', 'error');
return;
}
try {
// Fetch node data to get the node name for confirmation
console.log('🗑️ Fetching node data for deletion confirmation:', nodeId);
const nodeData = await window.apiJson(`/api/dashboard/farm-nodes/${nodeId}`, {
cache: 'no-store'
});
console.log('🗑️ Loaded node data for deletion:', nodeData);
// Set the pending delete node ID
window.pendingDeleteNodeId = nodeId;
// Update the modal with node information
const deleteNodeNameElement = document.getElementById('deleteNodeName');
if (deleteNodeNameElement) {
const nodeName = nodeData.name || `Node ${nodeId}`;
deleteNodeNameElement.textContent = nodeName;
}
// Show the delete confirmation modal
const deleteModal = new bootstrap.Modal(document.getElementById('deleteNodeModal'));
deleteModal.show();
} catch (error) {
console.error('🗑️ Error preparing node deletion:', error);
showNotification(`Failed to prepare node deletion: ${error.message}`, 'error');
}
}
/**
* Confirm node deletion (called from modal)
*/

View File

@@ -3,6 +3,9 @@
* Handles communication between users and providers.
*/
// Guard against redeclaration
if (typeof MessagingSystem === 'undefined') {
class MessagingSystem {
constructor() {
this.currentThread = null;
@@ -960,3 +963,5 @@ MessagingSystem.prototype.openThreadFromList = function(threadId) {
// Open the specific thread in the old modal
this.openThread(threadId);
};
} // End of MessagingSystem guard

View File

@@ -37,7 +37,121 @@
"deleted": null,
"deleted_at": null,
"deletion_reason": null,
"nodes": [],
"nodes": [
{
"id": "grid_node_1",
"location": "Unknown, Belgium",
"status": "Online",
"capacity": {
"cpu_cores": 56,
"memory_gb": 188,
"storage_gb": 135975,
"bandwidth_mbps": 1000,
"ssd_storage_gb": 1863,
"hdd_storage_gb": 134112,
"ram_gb": 188
},
"used_capacity": {
"cpu_cores": 25,
"memory_gb": 92,
"storage_gb": 1021,
"bandwidth_mbps": 0,
"ssd_storage_gb": 1021,
"hdd_storage_gb": 0,
"ram_gb": 92
},
"uptime_percentage": 99.0,
"farming_start_date": "2025-08-10T03:03:44.241167749Z",
"last_updated": "2025-09-09T03:03:44.241194575Z",
"utilization_7_day_avg": 65.0,
"slice_formats_supported": [
"1x1",
"2x2",
"4x4"
],
"rental_options": null,
"total_base_slices": 0,
"allocated_base_slices": 0,
"earnings_today_usd": 0.0,
"grid_node_id": "1",
"available_combinations": [],
"slice_allocations": [],
"slice_last_calculated": null,
"marketplace_sla": {
"id": "sla-repair-90a36bcd-b6e2-45e7-872a-baeaa485f220",
"name": "Repaired Node SLA",
"uptime_guarantee": 99.8,
"response_time_hours": 24,
"resolution_time_hours": 48,
"penalty_rate": 0.01,
"uptime_guarantee_percentage": 99.8,
"base_slice_price": 0.5,
"bandwidth_guarantee_mbps": 100.0,
"last_updated": "2025-09-09T03:04:23.227212978Z"
},
"slice_pricing": {
"base_price_per_hour": 1.0,
"currency": "USD",
"pricing_multiplier": 1.0
},
"grid_data": {
"capacity": {
"bandwidth_mbps": 1000,
"cpu_cores": 56,
"hdd_storage_gb": 134112,
"memory_gb": 188,
"ram_gb": 188,
"ssd_storage_gb": 1863,
"storage_gb": 135975
},
"certification_type": "Diy",
"city": "Unknown",
"country": "Belgium",
"farm_id": 1,
"farm_name": "Freefarm",
"farming_policy_id": 1,
"grid_node_id": 1,
"last_updated": "2025-09-09T03:03:44.240833231Z",
"location": "Unknown, Belgium",
"node_id": 1,
"public_ips": [
"192.168.1.100"
],
"status": "Online",
"total_resources": {
"bandwidth_mbps": 1000,
"cpu_cores": 56,
"hdd_storage_gb": 134112,
"memory_gb": 188,
"ram_gb": 188,
"ssd_storage_gb": 1863,
"storage_gb": 135975
},
"uptime": 99.5,
"used_resources": {
"bandwidth_mbps": 0,
"cpu_cores": 25,
"hdd_storage_gb": 0,
"memory_gb": 92,
"ram_gb": 92,
"ssd_storage_gb": 1021,
"storage_gb": 1021
}
},
"slice_formats": null,
"name": "Grid Node 1",
"region": "Belgium",
"node_type": "MyceliumNode",
"staking_options": null,
"availability_status": "Available",
"node_group_id": null,
"group_assignment_date": null,
"group_slice_format": null,
"group_slice_price": null,
"last_seen": "2025-09-09T03:03:44.241206636Z",
"health_score": 100.0
}
],
"resource_provider_earnings": [],
"resource_provider_settings": null,
"slice_products": [],