changes to the implementation bar
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user