Conexiones (features/connections)
Pantalla de administración de los canales del tenant: Web (widget), WhatsApp por QR e Instagram. Esta página es el índice de la feature; el detalle de cada componente, el modelo de canal y el flujo OAuth ya están documentados en la sección Meta y conexiones y no se repiten aquí. El backend de los endpoints está en Connection y Meta.
Ruta y permisos
shared/routes/content.routes.tscargaConnectionsModulebajoconnections(PAGE_URLS.CONNECTIONS) concanActivate: [AuthGuard, permissionGuard]ydata: { permission: 'CONNECTION_READ' }.connections-routing.module.tsrepitepermissionGuardy el mismo permiso en la ruta vacía, que renderizaConnectionsPageComponent.- Menú lateral: ítem
connections(sidebarMenu.connections) conpermission: 'CONNECTION_READ'encore/helpers/ui/nav.constant.ts.
| Acrónimo | Efecto en la UI |
|---|---|
CONNECTION_READ | Ruta y menú |
CONNECTION_CREATE | Botón "+" (selector de canal) y "Reautorizar" de Instagram |
CONNECTION_UPDATE | Editar, código de instalación, "Reconectar" |
CONNECTION_DELETE | Eliminar y "Cerrar sesión" de WhatsApp |
Todos se aplican con *appShowWithPermission en connections-table.component.html.
Archivos
| Archivo | Rol | Documentación |
|---|---|---|
connections.module.ts, connections-routing.module.ts | Declaran 7 componentes; importan NgbDropdownModule, NgbModalModule, NgbTooltipModule, NgSelectModule, TranslateModule, SharedModule | Esta página |
connections.constants.ts | CHANNEL_TYPE, CONNECTION_CHANNELS (web, WhatsApp QR e Instagram con enabled: true; WhatsApp Cloud y Facebook con enabled: false), insignias de estado, constantes del retorno OAuth (META_OAUTH_QUERY, META_OAUTH_RESULT, META_OAUTH_REASONS), META_NOT_CONFIGURED_CODE e INSTAGRAM_EXPIRY_WARNING_DAYS = 7 | Iconos de canal, OAuth de Instagram |
pages/connections-page | Breadcrumb y tabla; sin lógica | UI de conexiones |
components/connections-table | Grilla de tarjetas, paginación incremental, estado de sesión en vivo y acciones por canal | UI de conexiones |
components/connections-filter | Filtro por nombre y canal | UI de conexiones |
components/connection-channel-modal | Selector de canal (los deshabilitados muestran "Próximamente") | UI de conexiones |
components/connection-web-modal | Alta, edición y snippet del widget | UI de conexiones |
components/connection-whatsapp-modal | QR y formulario de atención | UI de conexiones |
components/connection-instagram-modal | Configuración posterior al OAuth | OAuth de Instagram |
Servicios
ConnectionService (core/services/api/connection.service.ts) concentra los endpoints /connections/* y POST /meta/oauth/instagram/authorize; la tabla completa de métodos está en UI de conexiones. El estado de la sesión de WhatsApp llega por ChatSocketService (whatsapp_qr y whatsapp_session_status, ver Sockets). La feature no usa un slice de NgRx: cada tabla mantiene su lista en memoria y recarga al cerrar un modal con closed.
Pruebas
| Spec | Cubre |
|---|---|
components/connections-table/connections-table.component.spec.ts | Enrutado del selector hacia el modal de WhatsApp, recarga al cerrar, parche en sitio de la tarjeta con whatsappSessionStatus$, estado por defecto init, "Cerrar sesión" solo tras confirmar |
components/connection-whatsapp-modal/connection-whatsapp-modal.component.spec.ts | Alta + arranque de sesión, reconexión sin recrear, eventos de socket filtrados por connectionId, avance al formulario tras connected, guardado de los seis campos y limpieza de conexiones huérfanas al destruir |
No hay specs para los modales web e Instagram, el filtro ni el selector de canal.
Gotchas
- La constante
INSTAGRAM_EXPIRY_WARNING_DAYS(7) y las de retorno OAuth se leen desde la tabla; el retorno de Meta llega como query params en/connections(ver OAuth de Instagram). - Cerrar el modal de WhatsApp sin guardar ni emparejar elimina la conexión que ese mismo modal creó.
- Los canales deshabilitados siguen apareciendo en el filtro porque este itera
CONNECTION_CHANNELScompleto. - El token de acceso de Meta nunca llega al frontend.
- Los iconos y colores de canal se reutilizan en el chat (ver Chat).