diff --git a/public/api.php b/public/api.php
index eccee64..4d3bdd0 100644
--- a/public/api.php
+++ b/public/api.php
@@ -140,7 +140,7 @@ try {
$installedVerData = file_exists("{$appDir}/version.json")
? json_decode((string)file_get_contents("{$appDir}/version.json"), true)
: [];
- $installedVer = $installedVerData['version'] ?? '1.4.3';
+ $installedVer = $installedVerData['version'] ?? '1.4.4';
echo json_encode([
'success' => true,
@@ -2311,14 +2311,25 @@ try {
$newVerJson = file_exists("{$appDir}/version.json")
? json_decode((string)file_get_contents("{$appDir}/version.json"), true)
- : ['version' => '1.3.8'];
+ : ['version' => '1.4.3'];
+
+ while (ob_get_level() > 0) {
+ @ob_end_clean();
+ }
+
+ header('Content-Type: application/json; charset=utf-8');
+ header('Cache-Control: no-cache, no-store, must-revalidate');
echo json_encode([
'success' => ($code === 0),
- 'new_version' => $newVerJson['version'] ?? '1.3.8',
+ 'new_version' => $newVerJson['version'] ?? '1.4.3',
'output' => $outputStr,
'message' => ($code === 0) ? "Mise à jour réussie !" : "Erreur lors de la mise à jour",
]);
+
+ if (function_exists('fastcgi_finish_request')) {
+ fastcgi_finish_request();
+ }
break;
default:
diff --git a/public/assets/app.js b/public/assets/app.js
index 95154e7..4c94be0 100644
--- a/public/assets/app.js
+++ b/public/assets/app.js
@@ -5962,72 +5962,106 @@ async function executeSystemUpdate() {
localStorage.removeItem('nexus_update_last_check_ts');
localStorage.removeItem('nexus_update_cached_data');
+ function finalizeUpdateSuccess(newVer) {
+ newVer = String(newVer || '').replace(/^v/, '');
+ localStorage.setItem('nexus_update_last_check_ts', Date.now().toString());
+ localStorage.setItem('nexus_update_cached_data', JSON.stringify({
+ success: true,
+ current_version: newVer,
+ latest_version: newVer,
+ has_update: false,
+ changelog: [],
+ release_date: ''
+ }));
+
+ const verTag = document.getElementById('system-version-tag');
+ const appBadge = document.getElementById('app-version-badge');
+ const headerUpdateBadge = document.getElementById('header-update-badge');
+ const pingDot = document.getElementById('update-ping-dot');
+
+ if (verTag && newVer) verTag.textContent = `v${newVer}`;
+ if (appBadge && newVer) appBadge.textContent = `v${newVer}`;
+ if (headerUpdateBadge) headerUpdateBadge.style.display = 'none';
+ if (btnRun) btnRun.style.display = 'none';
+ if (pingDot) pingDot.classList.add('hidden');
+
+ showToast(`NexusPBX a été mis à jour avec succès en v${newVer} ! Rechargement...`, 'success');
+ if (statusText) {
+ statusText.className = 'text-emerald-400 font-bold';
+ statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`;
+ }
+ if (btnModalConfirm) {
+ btnModalConfirm.className = 'px-5 py-2.5 rounded-xl text-xs font-bold bg-emerald-600 text-white flex items-center gap-2';
+ btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...';
+ }
+
+ setTimeout(() => {
+ closeUpdateConfirmModal();
+ window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now();
+ }, 1800);
+ }
+
try {
const res = await fetch('/api.php?action=run_update&_t=' + Date.now(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
- const data = await res.json();
- if (data.success) {
- const newVer = data.new_version || '';
-
- // 1. Mettre à jour immédiatement le cache avec l'état à jour
- localStorage.setItem('nexus_update_last_check_ts', Date.now().toString());
- localStorage.setItem('nexus_update_cached_data', JSON.stringify({
- success: true,
- current_version: newVer,
- latest_version: newVer,
- has_update: false,
- changelog: [],
- release_date: ''
- }));
-
- // 2. Mettre à jour visuellement les badges immédiatement
- const verTag = document.getElementById('system-version-tag');
- const appBadge = document.getElementById('app-version-badge');
- const headerUpdateBadge = document.getElementById('header-update-badge');
- const pingDot = document.getElementById('update-ping-dot');
-
- if (verTag && newVer) verTag.textContent = `v${newVer}`;
- if (appBadge && newVer) appBadge.textContent = `v${newVer}`;
- if (headerUpdateBadge) headerUpdateBadge.style.display = 'none';
- if (btnRun) btnRun.style.display = 'none';
- if (pingDot) pingDot.classList.add('hidden');
-
- showToast(`NexusPBX a été mis à jour avec succès en v${newVer} ! Rechargement...`, 'success');
- if (statusText) {
- statusText.className = 'text-emerald-400 font-bold';
- statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`;
- }
-
- if (btnModalConfirm) {
- btnModalConfirm.className = 'px-5 py-2.5 rounded-xl text-xs font-bold bg-emerald-600 text-white flex items-center gap-2';
- btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...';
- }
-
- // 3. Rechargement avec paramètre anti-cache pour forcer le navigateur à récupérer le nouveau DOM
- setTimeout(() => {
- closeUpdateConfirmModal();
- window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now();
- }, 1800);
- } else {
- closeUpdateConfirmModal();
- alert("Erreur lors de la mise à jour :\n\n" + (data.output || data.message));
- if (btnRun) {
- btnRun.disabled = false;
- btnRun.innerHTML = 'Réessayer la mise à jour';
- }
- if (btnModalConfirm) {
- btnModalConfirm.disabled = false;
- btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed');
- btnModalConfirm.innerHTML = 'Lancer la mise à jour (1-Clic)';
- }
+ const rawText = await res.text();
+ let data = null;
+ try {
+ data = JSON.parse(rawText);
+ } catch (_) {
+ data = null;
}
- } catch (e) {
+
+ if (data && data.success) {
+ finalizeUpdateSuccess(data.new_version);
+ return;
+ }
+
+ // Si la réponse n'était pas un JSON valide ou a été interrompue par le rechargement de php-fpm/nginx,
+ // on sonde le serveur pour vérifier si la mise à jour a en réalité bien été appliquée sur le disque
+ await new Promise(r => setTimeout(r, 2000));
+ try {
+ const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now());
+ const probeData = await probeRes.json();
+ if (probeData && probeData.success && probeData.current_version) {
+ finalizeUpdateSuccess(probeData.current_version);
+ return;
+ }
+ } catch (_) {}
+
+ // En cas d'échec réel avéré
closeUpdateConfirmModal();
- alert("Erreur réseau lors de la mise à jour : " + e.message);
+ const errMsg = (data && (data.output || data.message)) ? (data.output || data.message) : (rawText.slice(0, 150) || "Erreur inconnue");
+ alert("Erreur lors de la mise à jour :\n\n" + errMsg);
+ if (btnRun) {
+ btnRun.disabled = false;
+ btnRun.innerHTML = 'Réessayer la mise à jour';
+ }
+ if (btnModalConfirm) {
+ btnModalConfirm.disabled = false;
+ btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed');
+ btnModalConfirm.innerHTML = 'Lancer la mise à jour (1-Clic)';
+ }
+
+ } catch (e) {
+ // En cas d'interruption réseau du socket (Safari WebKit DOMException ou timeout),
+ // on vérifie avant d'alerter si le serveur a quand même réussi à déployer les fichiers
+ await new Promise(r => setTimeout(r, 2000));
+ try {
+ const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now());
+ const probeData = await probeRes.json();
+ if (probeData && probeData.success && probeData.current_version) {
+ finalizeUpdateSuccess(probeData.current_version);
+ return;
+ }
+ } catch (_) {}
+
+ closeUpdateConfirmModal();
+ alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue"));
if (btnRun) {
btnRun.disabled = false;
btnRun.innerHTML = 'Réessayer la mise à jour';
diff --git a/public/index.php b/public/index.php
index cf8485b..5795e45 100644
--- a/public/index.php
+++ b/public/index.php
@@ -18,7 +18,7 @@ $companyLogo = trim($branding['company_logo'] ?? '');
$hasBranding = !empty($companyName) || !empty($companyLogo);
$appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : [];
-$appVersion = $appVerData['version'] ?? '1.4.3';
+$appVersion = $appVerData['version'] ?? '1.4.4';
?>
diff --git a/scripts/update.sh b/scripts/update.sh
index 429cf94..aacacce 100755
--- a/scripts/update.sh
+++ b/scripts/update.sh
@@ -139,8 +139,14 @@ echo -e "${C_GRAY}[6/6] Rechargement à chaud d'Asterisk et des services web...$
asterisk -rx "core reload" >/dev/null 2>&1 || true
asterisk -rx "pjsip reload" >/dev/null 2>&1 || true
asterisk -rx "dialplan reload" >/dev/null 2>&1 || true
-systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true
-systemctl reload nginx 2>/dev/null || true
+
+# Rechargement des services web : différé si exécuté depuis l'interface web pour éviter de couper la requête HTTP
+if [ -t 1 ]; then
+ systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true
+ systemctl reload nginx 2>/dev/null || true
+else
+ (nohup bash -c "sleep 2 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true" >/dev/null 2>&1 &)
+fi
NEW_VER="Inconnue"
if [ -f "$APP_DIR/version.json" ]; then
diff --git a/version.json b/version.json
index e5efcf4..825e73d 100644
--- a/version.json
+++ b/version.json
@@ -1,12 +1,12 @@
{
- "version": "1.4.3",
+ "version": "1.4.4",
"codename": "Helios",
"release_date": "2026-11-04",
"min_php_version": "8.2",
"changelog": [
- "Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour (remplacement du confirm natif)",
- "Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion",
- "Boîte de connexion allégée en style verre dépoli transparent (Glassmorphism backdrop-blur)",
- "Nouveau fond d'écran immersif haute définition (réseau constellation)"
+ "Fiabilisation maximale de la mise à jour (rechargement web asynchrone non-bloquant et gestion d'erreurs tolérante)",
+ "Sonde automatique de secours évitant toute fausse alerte réseau sous Safari / WebKit lors du rechargement des services",
+ "Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour",
+ "Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion"
]
}