From 04448e34c2b279cd1c314ec19e3fbbfbb309dd51 Mon Sep 17 00:00:00 2001 From: Kobe Date: Mon, 16 Jun 2025 15:46:19 +0200 Subject: [PATCH] Update launch_progress.js --- static/js/launch_progress.js | 126 +++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/static/js/launch_progress.js b/static/js/launch_progress.js index c2536a6..49ea4c8 100644 --- a/static/js/launch_progress.js +++ b/static/js/launch_progress.js @@ -111,6 +111,18 @@ function initializeSteps() { `; stepsContainer.appendChild(saveDataStep); + + // Add Health Check step + const healthStep = document.createElement('div'); + healthStep.className = 'step-item'; + healthStep.innerHTML = ` +
+
+
Health Check
+

Verifying instance health...

+
+ `; + stepsContainer.appendChild(healthStep); } async function startLaunch(data) { @@ -368,9 +380,39 @@ async function startLaunch(data) { `; saveDataStep.querySelector('.step-content').appendChild(instanceDetails); + // After saving instance data, add the health check step + await updateStep(9, 'Health Check', 'Verifying instance health...'); + const healthResult = await checkInstanceHealth(`https://${data.webAddresses[0]}`); + + if (!healthResult.success) { + throw new Error(`Health check failed: ${healthResult.error}`); + } + + // Add a retry button if health check fails + const healthStep = document.querySelectorAll('.step-item')[8]; + if (!healthResult.success) { + const retryButton = document.createElement('button'); + retryButton.className = 'btn btn-sm btn-warning mt-2'; + retryButton.innerHTML = ' Retry Health Check'; + retryButton.onclick = async () => { + retryButton.disabled = true; + retryButton.innerHTML = ' Checking...'; + const retryResult = await checkInstanceHealth(`https://${data.webAddresses[0]}`); + if (retryResult.success) { + healthStep.classList.remove('failed'); + healthStep.classList.add('completed'); + retryButton.remove(); + } else { + retryButton.disabled = false; + retryButton.innerHTML = ' Retry Health Check'; + } + }; + healthStep.querySelector('.step-content').appendChild(retryButton); + } + } catch (error) { console.error('Launch failed:', error); - await updateStep(8, 'Saving Instance Data', `Error: ${error.message}`); + await updateStep(9, 'Health Check', `Error: ${error.message}`); showError(error.message); } } @@ -976,11 +1018,12 @@ function updateStep(stepNumber, title, description) { document.getElementById('currentStep').textContent = title; document.getElementById('stepDescription').textContent = description; - // Update progress bar - const progress = (stepNumber - 1) * 20; + // Calculate progress based on total number of steps (9 steps total) + const totalSteps = 9; + const progress = ((stepNumber - 1) / (totalSteps - 1)) * 100; const progressBar = document.getElementById('launchProgress'); progressBar.style.width = `${progress}%`; - progressBar.textContent = `${progress}%`; + progressBar.textContent = `${Math.round(progress)}%`; // Update step items const steps = document.querySelectorAll('.step-item'); @@ -1184,4 +1227,79 @@ async function saveInstanceData(instanceData) { console.error('Error saving instance data:', error); throw error; } +} + +async function checkInstanceHealth(instanceUrl) { + const maxRetries = 5; + let currentAttempt = 1; + + while (currentAttempt <= maxRetries) { + try { + // First get the instance ID from the database + const response = await fetch('/instances'); + const text = await response.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(text, 'text/html'); + + // Find the instance row that matches our URL + const instanceRow = Array.from(doc.querySelectorAll('table tbody tr')).find(row => { + const urlCell = row.querySelector('td:nth-child(7) a'); // URL is in the 7th column + return urlCell && urlCell.textContent.trim() === instanceUrl; + }); + + if (!instanceRow) { + throw new Error('Instance not found in database'); + } + + // Get the instance ID from the status badge's data attribute + const statusBadge = instanceRow.querySelector('[data-instance-id]'); + if (!statusBadge) { + throw new Error('Could not find instance ID'); + } + + const instanceId = statusBadge.dataset.instanceId; + + // Now use the instance ID to check status + const statusResponse = await fetch(`/instances/${instanceId}/status`); + if (!statusResponse.ok) { + throw new Error(`Health check failed with status ${statusResponse.status}`); + } + + const data = await statusResponse.json(); + + // Update the health check step + const healthStep = document.querySelectorAll('.step-item')[8]; // Adjust index based on your steps + healthStep.classList.remove('active'); + healthStep.classList.add('completed'); + const statusText = healthStep.querySelector('.step-status'); + + if (data.status === 'active') { + statusText.textContent = `Instance is healthy (Attempt ${currentAttempt}/${maxRetries})`; + return { + success: true, + data: data + }; + } else { + throw new Error('Instance is not healthy'); + } + } catch (error) { + console.error(`Health check attempt ${currentAttempt} failed:`, error); + + // Update status to show current attempt + const healthStep = document.querySelectorAll('.step-item')[8]; + const statusText = healthStep.querySelector('.step-status'); + statusText.textContent = `Health check failed (Attempt ${currentAttempt}/${maxRetries}): ${error.message}`; + + if (currentAttempt === maxRetries) { + return { + success: false, + error: `Health check failed after ${maxRetries} attempts: ${error.message}` + }; + } + + // Wait 5 seconds before next attempt + await new Promise(resolve => setTimeout(resolve, 5000)); + currentAttempt++; + } + } } \ No newline at end of file