fix(admin): resolve 'This page couldn't load' crash with auto chunk recovery, error boundaries, and null safety
This commit is contained in:
parent
93e915c341
commit
1bba620689
@ -41,54 +41,61 @@ SYNC_FILES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("[1/5] Verificando APK local...")
|
print("[1/5] Verificando APK local...", flush=True)
|
||||||
if not os.path.exists(LOCAL_APK):
|
if not os.path.exists(LOCAL_APK):
|
||||||
print(f" [ERROR] {LOCAL_APK} no encontrado.")
|
print(f" [ERROR] {LOCAL_APK} no encontrado.", flush=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
size_mb = os.path.getsize(LOCAL_APK) / (1024 * 1024)
|
size_mb = os.path.getsize(LOCAL_APK) / (1024 * 1024)
|
||||||
print(f" -> APK verificado: {LOCAL_APK} ({size_mb:.2f} MB)")
|
print(f" -> APK verificado: {LOCAL_APK} ({size_mb:.2f} MB)", flush=True)
|
||||||
|
|
||||||
print("[2/5] Git add, commit y push a origin main...")
|
print("[2/5] Git add, commit y push a origin main...", flush=True)
|
||||||
try:
|
try:
|
||||||
subprocess.run(["git", "add", "."], cwd=r"c:\Users\Carlos\dev\almeira-web", check=False)
|
subprocess.run(["git", "add", "."], cwd=r"c:\Users\Carlos\dev\almeira-web", check=False)
|
||||||
msg = "fix(admin): resolve 'This page couldn't load' crash with auto chunk recovery, error boundaries, and null safety"
|
msg = "fix(admin): resolve 'This page couldn't load' crash with auto chunk recovery, error boundaries, and null safety"
|
||||||
commit_res = subprocess.run(["git", "commit", "-m", msg], cwd=r"c:\Users\Carlos\dev\almeira-web", capture_output=True, text=True)
|
commit_res = subprocess.run(["git", "commit", "-m", msg], cwd=r"c:\Users\Carlos\dev\almeira-web", capture_output=True, text=True)
|
||||||
print(" -> Git commit:", (commit_res.stdout or commit_res.stderr or "OK").strip()[:200])
|
print(" -> Git commit:", (commit_res.stdout or commit_res.stderr or "OK").strip()[:150], flush=True)
|
||||||
push_res = subprocess.run(["git", "push", "origin", "main"], cwd=r"c:\Users\Carlos\dev\almeira-web", capture_output=True, text=True)
|
push_res = subprocess.run(["git", "push", "origin", "main"], cwd=r"c:\Users\Carlos\dev\almeira-web", capture_output=True, text=True)
|
||||||
print(" -> Git push:", (push_res.stdout or push_res.stderr or "OK").strip()[:200])
|
print(" -> Git push:", (push_res.stdout or push_res.stderr or "OK").strip()[:150], flush=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(" [WARN Git]:", e)
|
print(" [WARN Git]:", e, flush=True)
|
||||||
|
|
||||||
print("[3/5] Subiendo APK y archivos modificados al VPS vía SFTP...")
|
print("[3/5] Subiendo APK y archivos modificados al VPS vía SFTP...", flush=True)
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
ssh.connect(hostname=HOST, username=USER, password=PASSWORD, timeout=15)
|
ssh.connect(hostname=HOST, username=USER, password=PASSWORD, timeout=20)
|
||||||
sftp = ssh.open_sftp()
|
|
||||||
|
|
||||||
print(f" -> Subiendo APK ({size_mb:.2f} MB)...")
|
# 1. Crear directorios necesarios antes de abrir SFTP
|
||||||
|
dirs_to_make = set()
|
||||||
|
for rel in SYNC_FILES:
|
||||||
|
rem = f"{REMOTE_BASE}/{rel}"
|
||||||
|
dirs_to_make.add(os.path.dirname(rem))
|
||||||
|
for d in dirs_to_make:
|
||||||
|
ssh.exec_command(f"mkdir -p {d}")
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# 2. Abrir SFTP para subida
|
||||||
|
sftp = ssh.open_sftp()
|
||||||
|
print(f" -> Subiendo APK ({size_mb:.2f} MB)...", flush=True)
|
||||||
sftp.put(LOCAL_APK, REMOTE_APK)
|
sftp.put(LOCAL_APK, REMOTE_APK)
|
||||||
|
print(" -> APK subido al VPS.", flush=True)
|
||||||
|
|
||||||
for rel in SYNC_FILES:
|
for rel in SYNC_FILES:
|
||||||
loc = os.path.join(LOCAL_APP, rel.replace("/", os.sep))
|
loc = os.path.join(LOCAL_APP, rel.replace("/", os.sep))
|
||||||
rem = f"{REMOTE_BASE}/{rel}"
|
rem = f"{REMOTE_BASE}/{rel}"
|
||||||
rem_dir = os.path.dirname(rem)
|
if os.path.exists(loc):
|
||||||
try:
|
try:
|
||||||
# Crear directorio remoto si no existe
|
|
||||||
stdin, stdout, stderr = ssh.exec_command(f"mkdir -p {rem_dir}")
|
|
||||||
stdout.channel.recv_exit_status()
|
|
||||||
if os.path.exists(loc):
|
|
||||||
sftp.put(loc, rem)
|
sftp.put(loc, rem)
|
||||||
print(f" -> Sincronizado por SFTP: {rel}")
|
print(f" -> Sincronizado por SFTP: {rel}", flush=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" [WARN SFTP {rel}]:", e)
|
print(f" [WARN SFTP {rel}]:", e, flush=True)
|
||||||
|
|
||||||
sftp.close()
|
sftp.close()
|
||||||
|
|
||||||
print("[4/5] Identificando contenedor activo de DripZone y actualizando...")
|
print("[4/5] Identificando contenedor activo de DripZone y actualizando...", flush=True)
|
||||||
stdin, stdout, stderr = ssh.exec_command("docker ps --format '{{.Names}}'")
|
stdin, stdout, stderr = ssh.exec_command("docker ps --format '{{.Names}}'")
|
||||||
names = [n.strip() for n in stdout.read().decode('utf-8').splitlines() if n.strip()]
|
names = [n.strip() for n in stdout.read().decode('utf-8').splitlines() if n.strip()]
|
||||||
drip_containers = [n for n in names if "bfmno" in n or "drip" in n]
|
drip_containers = [n for n in names if "bfmno" in n or "drip" in n]
|
||||||
print(" Contenedores activos:", drip_containers)
|
print(" Contenedores activos:", drip_containers, flush=True)
|
||||||
|
|
||||||
for c in drip_containers:
|
for c in drip_containers:
|
||||||
ssh.exec_command(f"docker cp {REMOTE_APK} {c}:/app/public/DripZone.apk || true")
|
ssh.exec_command(f"docker cp {REMOTE_APK} {c}:/app/public/DripZone.apk || true")
|
||||||
@ -98,7 +105,7 @@ def main():
|
|||||||
rem_in_container_dir = os.path.dirname(f"/app/{rel}")
|
rem_in_container_dir = os.path.dirname(f"/app/{rel}")
|
||||||
ssh.exec_command(f"docker exec {c} mkdir -p {rem_in_container_dir} 2>/dev/null || true")
|
ssh.exec_command(f"docker exec {c} mkdir -p {rem_in_container_dir} 2>/dev/null || true")
|
||||||
ssh.exec_command(f"docker cp {loc} {c}:/app/{rel} 2>/dev/null || true")
|
ssh.exec_command(f"docker cp {loc} {c}:/app/{rel} 2>/dev/null || true")
|
||||||
print(f" -> Archivos copiados a: {c}")
|
print(f" -> Archivos copiados a: {c}", flush=True)
|
||||||
|
|
||||||
ssh.close()
|
ssh.close()
|
||||||
|
|
||||||
@ -107,11 +114,11 @@ def main():
|
|||||||
req = urllib.request.Request(APK_URL, method='HEAD')
|
req = urllib.request.Request(APK_URL, method='HEAD')
|
||||||
with urllib.request.urlopen(req, context=ctx, timeout=15) as res:
|
with urllib.request.urlopen(req, context=ctx, timeout=15) as res:
|
||||||
live_size = int(res.headers.get('Content-Length', 0)) / (1024 * 1024)
|
live_size = int(res.headers.get('Content-Length', 0)) / (1024 * 1024)
|
||||||
print(f" [OK] Verificado online: {APK_URL} (Status {res.status}, {live_size:.2f} MB)")
|
print(f" [OK] Verificado online: {APK_URL} (Status {res.status}, {live_size:.2f} MB)", flush=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" [WARN HEAD]: {e}")
|
print(f" [WARN HEAD]: {e}", flush=True)
|
||||||
|
|
||||||
print("[5/5] Enviando solución y APK al WhatsApp de Carlos (+57 316 745 5877)...")
|
print("[5/5] Enviando solución y APK al WhatsApp de Carlos (+57 316 745 5877)...", flush=True)
|
||||||
message_text = (
|
message_text = (
|
||||||
"🚀 *DripZone - Corrección de Error 'This page couldn't load' en Admin Productos*\n\n"
|
"🚀 *DripZone - Corrección de Error 'This page couldn't load' en Admin Productos*\n\n"
|
||||||
"¡Hola Carlos! Se diagnosticó y solucionó por completo la pantalla de error que experimentaste en `admin/productos`:\n\n"
|
"¡Hola Carlos! Se diagnosticó y solucionó por completo la pantalla de error que experimentaste en `admin/productos`:\n\n"
|
||||||
@ -123,7 +130,7 @@ def main():
|
|||||||
"• **Auto-Recuperación de Chunks (`ChunkLoadRecovery.tsx`)**: Si un usuario tiene una pestaña abierta durante un despliegue de Coolify, el sistema detecta la actualización de versión y recarga limpiamente la página en segundo plano sin mostrar ningún error.\n"
|
"• **Auto-Recuperación de Chunks (`ChunkLoadRecovery.tsx`)**: Si un usuario tiene una pestaña abierta durante un despliegue de Coolify, el sistema detecta la actualización de versión y recarga limpiamente la página en segundo plano sin mostrar ningún error.\n"
|
||||||
"• **Error Boundaries Oficiales (`admin/error.tsx` & `global-error.tsx`)**: Interfaz personalizada DripZone con diagnóstico claro y botón de recarga con bypass de caché para administradores.\n"
|
"• **Error Boundaries Oficiales (`admin/error.tsx` & `global-error.tsx`)**: Interfaz personalizada DripZone con diagnóstico claro y botón de recarga con bypass de caché para administradores.\n"
|
||||||
"• **Null Safety Reforzado**: Métodos de vigencia, ordenamiento y renderizado protegidos con validaciones defensivas.\n"
|
"• **Null Safety Reforzado**: Métodos de vigencia, ordenamiento y renderizado protegidos con validaciones defensivas.\n"
|
||||||
f"• **Catálogo Sincronizado**: 416 productos vigentes y 7 categorías activas y filtrables sin bloqueos.\n\n"
|
f"• **Catálogo Sincronizado**: 416 publicaciones vigentes y 7 categorías activas y filtrables sin bloqueos.\n\n"
|
||||||
f"📦 *APK Android Actualizado:* {APK_URL}\n\n"
|
f"📦 *APK Android Actualizado:* {APK_URL}\n\n"
|
||||||
"Te adjunto el APK limpio a continuación."
|
"Te adjunto el APK limpio a continuación."
|
||||||
)
|
)
|
||||||
@ -135,9 +142,9 @@ def main():
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(req_text, context=ctx, timeout=30) as resp:
|
with urllib.request.urlopen(req_text, context=ctx, timeout=30) as resp:
|
||||||
print(" [OK] Mensaje explicativo enviado a WhatsApp (Status:", resp.status, ")")
|
print(f" [OK] Mensaje explicativo enviado a WhatsApp (Status: {resp.status})", flush=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(" [Error texto WhatsApp]:", e)
|
print(" [Error texto WhatsApp]:", e, flush=True)
|
||||||
|
|
||||||
req_media = urllib.request.Request(
|
req_media = urllib.request.Request(
|
||||||
f"{EVOLUTION_API_URL}/message/sendMedia/{INSTANCE_NAME}",
|
f"{EVOLUTION_API_URL}/message/sendMedia/{INSTANCE_NAME}",
|
||||||
@ -153,11 +160,11 @@ def main():
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(req_media, context=ctx, timeout=120) as resp:
|
with urllib.request.urlopen(req_media, context=ctx, timeout=120) as resp:
|
||||||
print(" [OK] Documento APK enviado a WhatsApp (Status:", resp.status, ")")
|
print(f" [OK] Documento APK enviado a WhatsApp (Status: {resp.status})", flush=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(" [Error envío documento APK]:", e)
|
print(" [Error envío documento APK]:", e, flush=True)
|
||||||
|
|
||||||
print("\n✅ [DESPLIEGUE Y NOTIFICACIÓN COMPLETADOS EXITOSAMENTE]")
|
print("\n✅ [DESPLIEGUE Y NOTIFICACIÓN COMPLETADOS EXITOSAMENTE]", flush=True)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user