From 8b94e81dc8dbaa04ce63b58569114d2180154c0e Mon Sep 17 00:00:00 2001 From: josedario87 Date: Thu, 16 Oct 2025 22:56:15 -0600 Subject: [PATCH] =?UTF-8?q?Feature:=20Obtener=20iconos=20autom=C3=A1ticame?= =?UTF-8?q?nte=20de=20las=20aplicaciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Intentar meta_icon de Authentik primero - Buscar apple-touch-icon.png del dominio (PWA) - Intentar favicon.ico como fallback - Mostrar icono por defecto si todo falla - Sistema de retry inteligente para evitar requests duplicados --- .../app/components/auth/ApplicationsList.vue | 69 +++++++++++++++++-- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/nuxt4/app/components/auth/ApplicationsList.vue b/nuxt4/app/components/auth/ApplicationsList.vue index f9686b6..8aaf63d 100644 --- a/nuxt4/app/components/auth/ApplicationsList.vue +++ b/nuxt4/app/components/auth/ApplicationsList.vue @@ -57,10 +57,12 @@ >
- ([]) +// Estado para iconos fallidos (para no intentar cargarlos de nuevo) +const failedIcons = ref>(new Set()) + +// Función para obtener la URL del icono de una app +const getAppIconUrl = (app: Application): string | null => { + // Si el icono ya falló, no intentar de nuevo + if (failedIcons.value.has(app.pk)) { + return null + } + + // Si tiene meta_icon de Authentik, usarlo + if (app.icon) { + // Si es una URL completa + if (app.icon.startsWith('http://') || app.icon.startsWith('https://')) { + return app.icon + } + // Si es una ruta relativa, usar el dominio de la app + try { + const url = new URL(app.launchUrl) + return `${url.origin}${app.icon.startsWith('/') ? '' : '/'}${app.icon}` + } catch { + return null + } + } + + // Intentar obtener el favicon de la URL + try { + const url = new URL(app.launchUrl) + // Intentar primero apple-touch-icon (suele ser de mejor calidad) + return `${url.origin}/apple-touch-icon.png` + } catch { + return null + } +} + +// Manejar error al cargar icono +const handleIconError = (event: Event, app: Application) => { + const imgElement = event.target as HTMLImageElement + const currentSrc = imgElement.src + + // Marcar como fallido + failedIcons.value.add(app.pk) + + // Si estábamos intentando apple-touch-icon, intentar favicon.ico + if (currentSrc.includes('apple-touch-icon')) { + try { + const url = new URL(app.launchUrl) + imgElement.src = `${url.origin}/favicon.ico` + failedIcons.value.delete(app.pk) // Dar otra oportunidad + return + } catch { + // Si falla, el v-else mostrará el icono por defecto + } + } + + // Ocultar la imagen para que se muestre el icono por defecto + imgElement.style.display = 'none' +} + // Extraer todos los grupos únicos de las aplicaciones const availableGroups = computed(() => { const groups = new Set()