changes to the implementation bar

This commit is contained in:
2026-08-26 23:13:57 +02:00
parent 478ee327c2
commit 495b4ae20c
+97 -81
View File
@@ -507,9 +507,8 @@
formState.style.display = 'none';
loadingState.style.display = 'block';
// Fixiert auf genau 90 Sekunden (1:30 Min.)
const estimatedSec = result.estimated_seconds || 90;
startPolling(tenantSlug, estimatedSec);
// Startet den fixierten 90 Sekunden Prozess
startProvisioningProcess(tenantSlug);
} catch (error) {
errorAlert.textContent = error.message;
@@ -519,94 +518,114 @@
}
});
function startPolling(slug, estimatedSeconds) {
// Exakt auf die Prozessschritte aus dem Log abgestimmte Statusmeldungen für den 90s Ablauf
function startProvisioningProcess(slug) {
const totalDurationMs = 90 * 1000; // Exakt 1:30 Minuten (90 Sekunden)
let startTime = Date.now();
let backendData = null; // Speichert das finale Backend-Resultat
let isFailed = false;
// Echte Log-Meldungen, die exakt alle 10 Sekunden durchgeschaltet werden
const statusSteps = [
{ time: 0, msg: "Trigger verarbeitet: Starte Provisionierung für " + slug + "..." },
{ time: 8, msg: "Freier Netzwerk-Port wird zugewiesen (Port 10004)..." },
{ time: 18, msg: "Certbot & Let's Encrypt: SSL-Zertifikat wird angefordert..." },
{ time: 32, msg: "SSL-Zertifikat ausgestellt & Nginx VirtualHost konfiguriert..." },
{ time: 42, msg: "Starte Anwendungs-Container (Docker Stack / MongoDB / Redis)..." },
{ time: 54, msg: "Datenbank initialisiert. Standard-Admin wird angelegt..." },
{ time: 64, msg: "Konfiguriere gebuchte Module (Bibliothek = ON)..." },
{ time: 74, msg: "Führe automatischen Systemneustart (restart.sh) durch..." },
{ time: 84, msg: "Bereinige verwaiste App-Container & schließe Setup ab..." }
{ atMs: 0, msg: "[INFO] Verarbeite Trigger: Starte Provisionierung für " + slug + "..." },
{ atMs: 10000, msg: "[INFO] Prüfe freie Ports... Verwende Port 10004 für Tenant " + slug },
{ atMs: 20000, msg: "Requesting a certificate for " + slug + ".invario-software.de..." },
{ atMs: 30000, msg: "Successfully deployed certificate to Nginx. Restarting app container..." },
{ atMs: 40000, msg: "Container inventarsystem-app-1 Recreated. Waiting for MongoDB/Redis..." },
{ atMs: 50000, msg: "Initializing database for " + slug + "... Default admin created." },
{ atMs: 60000, msg: "Module configurations updated successfully (library=on)..." },
{ atMs: 70000, msg: "Rebuilding and/or restarting app container using docker-compose..." },
{ atMs: 80000, msg: "[INFO] Bereinige verwaiste App-Container. Cleaning up old temporary files..." }
];
let msgIdx = 0;
statusText.textContent = statusSteps[0].msg;
// Zeit-getriebenes Update der Status-Texte
const msgInterval = setInterval(() => {
msgIdx++;
if (msgIdx < statusSteps.length) {
statusText.textContent = statusSteps[msgIdx].msg;
} else {
clearInterval(msgInterval);
// 1. Hintergrund-Polling: Fragt den echten Status ab, OHNE die UI abzubrechen
const checkBackend = async () => {
if (isFailed) return;
try {
const res = await fetch(`/instance_request/status?slug=${slug}`);
const data = await res.json();
// Wenn Backend fertig ist, Daten merken, aber Timer weiterlaufen lassen!
if (data.status === 'ready' || data.status === 'active') {
backendData = data;
} else if (data.status === 'failed' || data.status === 'error') {
isFailed = true;
handleError("Fehler bei der Bereitstellung auf dem Server gemeldet.");
} else {
// Wenn noch nicht fertig, in 4 Sekunden nochmal fragen
if (!backendData) setTimeout(checkBackend, 4000);
}
} catch (err) {
if (!backendData) setTimeout(checkBackend, 4000);
}
}, (estimatedSeconds * 1000) / statusSteps.length);
// Fortschrittsbalken-Animation (0% -> 99% gleichmäßig verteilt über 90 Sekunden)
let elapsedMs = 0;
const totalMs = estimatedSeconds * 1000;
};
const progressInterval = setInterval(() => {
elapsedMs += 200;
let currentPercent = Math.min(99, Math.floor((elapsedMs / totalMs) * 100));
progressBar.style.width = currentPercent + '%';
progressPercent.textContent = currentPercent + '%';
}, 200);
// Starte das Polling nach 5 Sekunden
setTimeout(checkBackend, 5000);
// Polling-Logik zur Abfrage beim Backend
let retryCount = 0;
const maxRetries = 60; // 60 * 3s = 180s maximale Pufferzeit
const checkStatus = async () => {
retryCount++;
if (retryCount > maxRetries) {
handleError("Die Bereitstellung dauert länger als erwartet. Sie erhalten eine E-Mail, sobald die Instanz bereit ist.");
// 2. Der strikte visuelle 90-Sekunden Timer (läuft in einer Endlosschleife bis die 90s voll sind)
const uiInterval = setInterval(() => {
if (isFailed) {
clearInterval(uiInterval);
return;
}
try {
const res = await fetch(`/instance_request/status?slug=${slug}`);
if (!res.ok) throw new Error("Netzwerkfehler");
const data = await res.json();
let elapsedMs = Date.now() - startTime;
// A. Fortschrittsbalken berechnen (geht maximal bis 99% während der Wartezeit)
let currentPercent = Math.min(99, Math.floor((elapsedMs / totalDurationMs) * 100));
progressBar.style.width = currentPercent + '%';
progressPercent.textContent = currentPercent + '%';
if (data.status === 'ready' || data.status === 'active') {
clearInterval(msgInterval);
clearInterval(progressInterval);
// Abschlussanimation auf 100%
progressBar.style.width = '100%';
progressBar.style.background = '#1b8a3e';
progressPercent.textContent = '100%';
statusText.textContent = "[SUCCESS] Tenant bereitgestellt: " + slug + " (Port: 10004)";
statusText.style.color = '#1b8a3e';
setTimeout(() => {
showSuccessState(
data.url || `https://${slug}.invario-software.de`,
data.username || "admin",
data.password || "admin123",
data.invoice_url
);
}, 1000);
} else if (data.status === 'failed' || data.status === 'error') {
handleError("Fehler bei der Bereitstellung. Bitte kontaktieren Sie den Support.");
} else {
setTimeout(checkStatus, 3000);
}
} catch (err) {
setTimeout(checkStatus, 3000);
// B. Den passenden Text basierend auf der vergangenen Zeit heraussuchen
let currentStep = statusSteps.slice().reverse().find(step => elapsedMs >= step.atMs);
if (currentStep && statusText.textContent !== currentStep.msg) {
statusText.textContent = currentStep.msg;
}
};
// C. Die vollen 90 Sekunden sind abgelaufen
if (elapsedMs >= totalDurationMs) {
clearInterval(uiInterval); // Timer stoppen
if (backendData) {
// Backend ist fertig -> Abschluss initiieren
finishProcess(backendData);
} else {
// Fallback: Falls das Backend nach 90s ausnahmsweise noch lädt
statusText.textContent = "Warte auf finale Bestätigung des Servers (dies kann noch einen kurzen Moment dauern)...";
const waitInterval = setInterval(() => {
if (backendData) {
clearInterval(waitInterval);
finishProcess(backendData);
} else if (isFailed) {
clearInterval(waitInterval);
}
}, 2000);
}
}
}, 100); // 100ms Interval für sehr weiche Animation des Balkens
// 3. Abschluss-Funktion (wird nur aufgerufen, wenn 90s vorbei SIND und Backend ready IST)
function finishProcess(data) {
progressBar.style.width = '100%';
progressBar.style.background = '#1b8a3e';
progressPercent.textContent = '100%';
statusText.textContent = "[SUCCESS] System erfolgreich neu gestartet für " + slug + ".";
statusText.style.color = '#1b8a3e';
// Nach 1,5 Sekunden auf den Success-Screen wechseln
setTimeout(() => {
showSuccessState(
data.url || `https://${slug}.invario-software.de`,
data.username || "admin",
data.password || "admin123",
data.invoice_url
);
}, 1500);
}
// 4. Fehler-Behandlung (bricht sofort ab)
function handleError(message) {
clearInterval(msgInterval);
clearInterval(progressInterval);
clearInterval(uiInterval);
statusText.textContent = message;
statusText.style.color = '#b02a37';
progressBar.style.background = '#b02a37';
@@ -615,9 +634,6 @@
statusText.insertAdjacentHTML('afterend', '<br><button id="retry-btn" onclick="window.location.reload();" class="btn secondary" style="margin-top:1.5rem;">Seite neu laden</button>');
}
}
// Erstes Polling nach 5 Sekunden starten
setTimeout(checkStatus, 5000);
}
function showSuccessState(url, user, pass, invoiceUrl) {