diff --git a/signet-dashboard/public/app.js b/signet-dashboard/public/app.js index 0b64cae..3b30b91 100644 --- a/signet-dashboard/public/app.js +++ b/signet-dashboard/public/app.js @@ -69,6 +69,7 @@ async function loadData() { loadLatestBlock(), loadWalletBalance(), loadAnchorCount(), + loadAvailableForAnchor(), loadNetworkPeers(), loadMiningDifficulty(), loadAvgBlockTime(), @@ -187,6 +188,53 @@ async function loadAnchorCount() { } } +/** + * Charge la capacité d'ancrage restante + */ +async function loadAvailableForAnchor() { + const availableForAnchorValue = document.getElementById('available-for-anchor-value'); + const availableForAnchorSpinner = document.getElementById('available-for-anchor-spinner'); + const confirmedAvailableForAnchorValue = document.getElementById('confirmed-available-for-anchor-value'); + + if (!availableForAnchorValue || !availableForAnchorSpinner || !confirmedAvailableForAnchorValue) { + console.error('Elements for available-for-anchor not found in DOM'); + return; + } + + // Afficher le spinner + availableForAnchorSpinner.style.display = 'inline'; + availableForAnchorValue.textContent = '...'; + confirmedAvailableForAnchorValue.textContent = '...'; + + try { + const response = await fetch(`${API_BASE_URL}/api/utxo/list`); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + const counts = data.counts || {}; + const availableForAnchor = counts.availableForAnchor || 0; + const confirmedAvailableForAnchor = counts.confirmedAvailableForAnchor || 0; + + // Masquer le spinner et mettre à jour les valeurs + availableForAnchorSpinner.style.display = 'none'; + availableForAnchorValue.textContent = availableForAnchor.toLocaleString('fr-FR') + ' ancrages'; + confirmedAvailableForAnchorValue.textContent = confirmedAvailableForAnchor.toLocaleString('fr-FR'); + } catch (error) { + console.error('Error loading available for anchor:', error); + // Masquer le spinner + availableForAnchorSpinner.style.display = 'none'; + // Afficher une valeur par défaut en cas d'erreur + const currentValue = availableForAnchorValue.textContent; + if (currentValue === '-' || currentValue === 'Erreur' || currentValue === '...') { + availableForAnchorValue.textContent = '0 ancrages'; + } + confirmedAvailableForAnchorValue.textContent = '0'; + } +} + /** * Charge les informations sur les pairs */ @@ -476,11 +524,21 @@ function handleFileSelect(event) { if (file) { selectedFile = file; const fileInfo = document.getElementById('file-info'); - fileInfo.innerHTML = ` + const maxSize = 100 * 1024 * 1024; // 100 MB en bytes + const fileSize = file.size; + const isOverLimit = fileSize > maxSize; + + let infoHtml = ` Fichier sélectionné : ${file.name}
Taille : ${formatFileSize(file.size)}
Type : ${file.type || 'Non spécifié'} `; + + if (isOverLimit) { + infoHtml += `
⚠️ Fichier trop volumineux (limite : 100 MB)`; + } + + fileInfo.innerHTML = infoHtml; } } @@ -537,34 +595,64 @@ async function generateHashFromFile() { return; } + // Vérifier la taille du fichier (limite : 100 MB) + const maxSize = 100 * 1024 * 1024; // 100 MB en bytes + if (selectedFile.size > maxSize) { + showResult('anchor-result', 'error', `Le fichier est trop volumineux (${formatFileSize(selectedFile.size)}). La limite est de 100 MB.`); + return; + } + try { const reader = new FileReader(); - reader.onload = async (e) => { - const fileContent = e.target.result; - try { - const response = await fetch(`${API_BASE_URL}/api/hash/generate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ fileContent }), - }); + await new Promise((resolve, reject) => { + reader.onload = async (e) => { + try { + const arrayBuffer = e.target.result; + // Convertir l'ArrayBuffer en base64 pour l'envoi au backend + // Utiliser une boucle pour éviter les limites de taille des arguments de fonction + const uint8Array = new Uint8Array(arrayBuffer); + let binaryString = ''; + for (let i = 0; i < uint8Array.length; i++) { + binaryString += String.fromCharCode(uint8Array[i]); + } + const base64 = btoa(binaryString); - const data = await response.json(); + const response = await fetch(`${API_BASE_URL}/api/hash/generate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ fileContent: base64, isBase64: true }), + }); - if (data.hash) { - document.getElementById('anchor-hash').value = data.hash; - showResult('anchor-result', 'success', `Hash généré avec succès : ${data.hash}`); - } else { - showResult('anchor-result', 'error', 'Erreur lors de la génération du hash.'); + if (!response.ok) { + const errorData = await response.json().catch(() => ({ error: `HTTP ${response.status}: ${response.statusText}` })); + throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.hash) { + document.getElementById('anchor-hash').value = data.hash; + showResult('anchor-result', 'success', `Hash généré avec succès : ${data.hash}`); + } else { + showResult('anchor-result', 'error', data.error || 'Erreur lors de la génération du hash.'); + } + resolve(); + } catch (error) { + showResult('anchor-result', 'error', `Erreur : ${error.message}`); + reject(error); } - } catch (error) { - showResult('anchor-result', 'error', `Erreur : ${error.message}`); - } - }; + }; - reader.readAsText(selectedFile); + reader.onerror = (error) => { + showResult('anchor-result', 'error', `Erreur lors de la lecture du fichier : ${error.message || 'Erreur inconnue'}`); + reject(error); + }; + + reader.readAsArrayBuffer(selectedFile); + }); } catch (error) { showResult('anchor-result', 'error', `Erreur lors de la lecture du fichier : ${error.message}`); } diff --git a/signet-dashboard/public/index.html b/signet-dashboard/public/index.html index 9af9001..53bdbdb 100644 --- a/signet-dashboard/public/index.html +++ b/signet-dashboard/public/index.html @@ -65,6 +65,16 @@

+
+

Capacité d'Ancrage Restante

+

+ - + +

+

+ - UTXOs confirmés +

+

Nombre de Pairs

-

@@ -118,6 +128,9 @@
+

+ Limite de taille : 100 MB maximum +

@@ -209,8 +222,8 @@

Bitcoin Ancrage Dashboard - Équipe 4NK

Dernière mise à jour : -

- - + +