Funcionalidad: Custo-manifest (Rainbow Extensions) — Extensiones de la interfaz gráfica de usuario
Licencia: Licencia Business como mínimo
Puede utilizar este artículo para crear extensiones de la interfaz gráfica de usuario de Rainbow que añadan botones, widgets y aplicaciones web integradas a Rainbow. Verá cuáles son los puntos de extensión disponibles y cómo elegir la ubicación adecuada para su flujo de trabajo.
Descripción general
Las extensiones de la interfaz gráfica de usuario le permiten añadir botones personalizados, mostrar widgets y aplicaciones web integradas en la interfaz de Rainbow. Estas extensiones requieren, como mínimo, una licencia Business.
Qué puede hacer con las extensiones de la interfaz gráfica de usuario:
- Añadir botones de acción en los que se puede hacer clic en las listas de contactos, el registro de llamadas, la ficha de comunicación y las Burbujas
- Mostrar contenido personalizado (datos de CRM, tickets, Informes) de forma automática en ventanas emergentes de llamadas y paneles de contactos
- Incrustar una aplicación web de terceros directamente en el panel principal de Rainbow
Tipos de puntos de extensión
Un punto de extensión (EP) es un espacio designado en la interfaz de Rainbow donde se puede adjuntar una acción personalizada. Cada EP tiene una clave única (p. ej., on-contact-list-actions), una ubicación fija en la interfaz de usuario y reglas que determinan qué campos y variables son disponibles. El archivo «custo-manifest» declara una o varias acciones bajo cada clave de EP.
Botones: botones en los que se puede hacer clic
Se inserta un botón con icono en una ubicación específica de la interfaz de usuario de Rainbow. Al hacer clic, se ejecuta una acción y, opcionalmente, se muestra su resultado en una ventana emergente (Markdown o Adaptive Card). Se admiten hasta 3 botones por punto de extensión.
| Punto de extensión | Ubicación del botón |
|---|---|
| acciones-de-los-botones-en-una-llamada-entrante-de-pbx | Ventana emergente de llamada entrante |
| on-call-log-list-actions | Cada fila del registro de llamadas |
| Acciones en la lista de contactos | Cada fila de la lista de contactos |
| Acciones en los detalles de contacto | Panel de detalles del contacto |
| Acciones en la ficha de comunicación | Barra del gestor de llamadas |
| Acciones en la burbuja | Menú de propiedades de la burbuja |
| Acciones de conferencia en la burbuja | Menú de conferencia telefónica |
| Acciones del menú de usuario | Menú de usuario (BETA, escritorio/web — no Teams) |
Visualizaciones: visualización automática de información
El contenido (Markdown o Adaptive Card) se inserta automáticamente en una ubicación específica de la interfaz de usuario, sin necesidad de intervención por parte del usuario. El contenido se recupera cuando la ubicación se hace visible.
| Punto de extensión | Ubicación de visualización |
|---|---|
| on-incoming-pbx-call-display-actions | En la ventana emergente de llamada entrante |
| on-contact-card-display-actions | En el panel de detalles del contacto |
| acciones-de-visualización-en-el-widget-principal | Widget en el panel principal de Rainbow |
| Acciones de visualización en la pantalla principal | Mensaje en la aplicación web de Teams |
Visualización en marco: aplicación web de terceros
Incorpora una aplicación web de terceros dentro de un marco de la interfaz de usuario de Rainbow. Con Popup: true, la aplicación se abre en una ventana del navegador en lugar de integrarse.
| Punto de extensión | Ubicación |
|---|---|
| on-main-window-actions | Marco en la ventana principal de Rainbow |
Configuración de una extensión de interfaz gráfica de usuario
El «custo-manifest» es un objeto JSON con la siguiente estructura:
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"<EXTENSION-POINT-KEY>": [
{
"name": "...",
"icon": "...",
"command": {
"url": "...",
"params": "...",
"commandType": "rest",
"method": "GET"
},
"responseType": "markdown"
}
]
}
}Normas generales:
- la versión debe ser «2».
- jsonType debe ser «Rainbow-custo-manifest». Dentro de un archivo ZIP, este campo identifica qué archivo JSON es el manifiesto.
- Cada clave bajo «extension-points» es una matriz: un máximo de tres acciones por punto de extensión.
- Cada acción debe contener un objeto de comando válido. «name» e «icon» son obligatorios en función del punto de extensión (véase el apartado 3.4).
Campos de la acción
| Campo | Posición | Descripción |
|---|---|---|
| nombre | raíz | Texto que se muestra (etiqueta de botón, título de widget, etiqueta de menú). Obligatorio en función del EP. |
| icono / iconId | root | Icono del botón (URL, ${custo.path}\... o sprite integrado). Obligatorio para los botones con icono. |
| tooltip | raíz | Texto de la información sobre herramientas. Opcional. |
| comando | raíz | Objeto de comando (véase el apartado 3.2). Siempre obligatorio. |
| responseType | raíz | «markdown» (por defecto), «json» o «adaptiveCard». Obligatorio para los EP de visualización; opcional para los botones. |
| displayJsonField | raíz | Si responseType es «json», nombre del campo JSON que contiene el código Markdown que se va a mostrar. |
| adaptiveCardTemplate | raíz | Plantilla de Adaptive Card con JSON en línea. |
| adaptiveCardTemplateJsonField | raíz | Nombre del campo de la respuesta REST que contiene la plantilla de Adaptive Card. |
| adaptiveCardContentJsonField | raíz | Nombre del campo de la respuesta REST que contiene los datos de la tarjeta. |
| adaptiveCardSubmitUrl | root | URL REST a la que se envía una solicitud POST cuando se invoca Action.Submit en la tarjeta. |
El objeto de comando
El objeto de comando es siempre obligatorio y debe contener, como mínimo, una URL. Dependiendo del «commandType» elegido, pueden ser válidos subcampos adicionales.
"command": {
"url": "{{server}}/your-endpoint",
"params": "user=${localUser.email}",
"commandType": "rest",
"method": "GET",
"header": ["Authorization: Bearer TOKEN"],
"bodyParameters": { "key": "value" }
}| Campo | Cuándo utilizarlo |
|---|---|
| url | Obligatorio. Ruta de la aplicación, URL web, archivo o API REST. |
| params | Opcional. Se añaden después de «?» para GET, o como parámetros de URL. Se admiten variables. |
| commandType | Opcional. Por defecto «rest». Valores: «rest», «file» (dependiendo del EP). |
| método | Opcional (solo si commandType: «rest»). Valores: «GET», «POST». |
| encabezado | Opcional (si se trata de REST). Matriz de cadenas del tipo «Nombre-del-encabezado: valor» que se insertan como encabezados HTTP. |
| parámetros del cuerpo | Obligatorio si el método es «POST». Objeto JSON enviado como cuerpo. Se admiten variables. |
Variables de Rainbow
Las variables $ se sustituyen en tiempo de ejecución por su valor real. Pueden aparecer en command.url, command.params, command.bodyParameters y en el contenido devuelto a la extensión para su visualización.
Sintaxis
${object.attribute}
${object.attribute.regex(pattern)}
${object.attribute.regex(pattern, replacement)}Objetos y atributos disponibles
Usuario de Rainbow (ME)
${localUser.firstName} ${localUser.lastName}
${localUser.email} ${localUser.canonicalNumber}
${localUser.phoneNumber} ${localUser.internalNumber}
${localUser.phonePbx} ${localUser.nickname}
${localUser.correoDeInicioDeSesión} ${localUser.id}Contacto (si está identificado)
${contacto.nombre} ${contacto.apellidos}
${contacto.númeroDeTeléfono} ${contacto.correoElectrónico}
${contact.company} ${contact.workNumber}
${contact.mobileNumber} ${contact.personalNumber}
${contact.personalMobile}
${contact.tags} (concatenadas, separadas por comas)Persona que llama (solo en los EP del botón de llamada)
${caller.firstName} ${caller.lastName} ${caller.phoneNumber}Destinatario (solo en EP con botón de llamada)
${called.phoneNumber}Contexto de la llamada (solo para EP con botón de llamada)
${call.callId}
${call.globalCallId} (solo OXE)
${call.correlator}Burbuja (solo en EP de Burbuja)
${bubble.ownerEmail} ${bubble.name} ${bubble.shareLink}
${bubble.id}
${bubble.miembros} (JSON — solo con commandType: «rest»)Compatibilidad por punto de extensión
| Punto de extensión | Objetos variables permitidos |
|---|---|
| on-incoming-pbx-call-button-actions | localUser, caller, called, call, Contacto |
| on-call-log-list-actions | localUser, Contacto |
| acciones en la lista de contactos | usuario local, contacto |
| acciones en los detalles de contacto | usuario local, contacto |
| acciones en la ficha de comunicación | usuario local, persona que llama, persona llamada, llamada, Contacto |
| acciones en la burbuja | usuario local, Burbuja |
| acciones en la burbuja de conferencia | usuario local, Burbuja |
| acciones en el menú del usuario | localUser |
| acciones-al-mostrarse-una-llamada-entrante-de-la-centralita | usuario local, persona que llama, persona llamada, llamada, Contacto |
| acciones al mostrar la ficha de contacto de Contactos | usuario local, contacto |
| acciones de visualización en el widget principal | usuario local |
| acciones-de-visualización-en-la-pantalla-principal | usuario local |
| acciones-en-la-ventana-principal | usuario local |
modificador de expresiones regulares
Aplica una expresión regular al valor de la variable antes de la sustitución:
// Normalizar un número: sustituir +33 o +1 por 0
"params": "pbx=${localUser.phonePbx.regex(^\+33|^\+1, 0)}"
// Sustituya el dominio del correo electrónico
"params": "byEmail=${localUser.email.regex(alcatel.com, al-enterprise.com)}"
// Extraiga los últimos 9 dígitos (sin sustitución = extracción)
"params": "${contacto.phoneNumber.regex(.{0,9}$)}"Variable ${time}
Disponible en todos los puntos de extensión; se sustituye en el momento en que se ejecuta la acción.
| Variable | Valor |
|---|---|
| ${time} | Fecha y hora completas (ISO 8601, p. ej., 2026-05-18T15:30:45.123Z) |
| ${time.year} | Año — 4 dígitos |
| ${time.month} | Mes: del 01 al 12 |
| ${time.day} | Día — 01-31 |
| ${time.hour} | Hora — 00-23 |
| ${time.minute} | Minuto — 00-59 |
| ${time.second} | Segundo — 00-59 |
| ${time.millisec} | Milisegundos — 000-999 |
Recursos locales — ${custo.path}
Para distribuir un manifiesto con archivos locales (iconos, contenido estático):
- Haga referencia a cada recurso como ${custo.path}\\nombre-del-archivo.ext
- Empaquete el archivo `custo-manifest.json` y los archivos de recursos en un ZIP (con el manifiesto en la raíz)
{
"icon": "${custo.path}\\crm.png",
"command": {
"commandType": "file",
"url": "${custo.path}\\content.txt"
},
"responseType": "markdown"
}Campos específicos de la extensión
| Campo | Puntos de extensión afectados | Descripción |
|---|---|---|
| AnswerOnClick | acciones del botón de llamada entrante de la centralita | true → ejecuta la acción y responde a la llamada con un solo clic |
| Ventana emergente | Acciones en la ventana principal | true → abre la aplicación web en una ventana del navegador en lugar de en el marco de Rainbow |
| tambiénParaEquipos | acciones-en-la-lista-de-registro-de-llamadas, acciones-en-la-pantalla-principal | También muestra la extensión en el complemento de Teams |
| urlConfig | acciones-en-la-pantalla-principal-del-widget | URL HTTP/HTTPS para la configuración del widget |
Incluir recursos locales (archivo ZIP)
Si la acción hace referencia a archivos locales (iconos o archivos de visualización), incluya el archivo custo-manifest.json junto con dichos archivos en un archivo .zip antes de importarlos.
Estructura ZIP requerida: el archivo «manifest» debe encontrarse en la raíz:
my-manifest.zip
├── custo-manifest.json
├── icon.png
└── display-content.txtImplementación del manifiesto
Una vez configurado el manifiesto, impleméntelo a través de la consola de administración de Rainbow o de forma local. Consulte «Implementación de un custo-manifest en Rainbow».
Ejemplos de configuración
Botones
Compatibles con Rainbow Desktop y Rainbow Web; requieren CORS para las llamadas REST.
Ejemplo 1: «on-contact-list-actions» añade un botón en cada fila de contacto que abre el contacto en un CRM externo (sin ventana emergente dentro de Rainbow):
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-contact-list-actions": [
{
"name": "Abrir en CRM",
"tooltip": "Ver este contacto en nuestro CRM",
"icon": "${custo.path}\\crm.png",
"command": {
"url": "https://crm.example.com/contact",
"params": "email=${contact.email}&phone=${contact.phoneNumber}"
}
}
]
}
}Ejemplo 2: «on-incoming-pbx-call-button-actions» añade un botón en la ventana emergente de llamadas entrantes que crea un ticket y responde a la llamada con un solo clic:
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-incoming-pbx-call-button-actions": [
{
"name": "Crear ticket y responder",
"AnswerOnClick": true,
"command": {
"commandType": "rest",
"method": "POST",
"url": "https://tickets.example.com/api/tickets",
"header": [
"Authorization: Bearer TOKEN",
"Content-Type: application/json"
],
"bodyParameters": {
"caller": "${caller.phoneNumber}",
"callId": "${call.callId}",
"createdBy": "${localUser.loginEmail}"
}
}
}
]
}
}Se muestra
Compatible con Rainbow Desktop y Rainbow Web; requiere CORS para las llamadas REST.
Ejemplo 1: «on-incoming-pbx-call-display-actions» muestra automáticamente una ficha de identificador de llamada en formato Markdown en la ventana emergente de llamadas entrantes:
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-incoming-pbx-call-display-actions": [
{
"command": {
"commandType": "rest",
"method": "GET",
"url": "https://api.example.com/lookup",
"params": "phone=${caller.phoneNumber}",
"header": ["Authorization: Bearer TOKEN"]
},
"responseType": "markdown"
}
]
}
}Ejemplo 2: «on-main-widget-display-actions» muestra un widget de Adaptive Card en el panel principal de Rainbow, que se actualiza cada vez que se abre:
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-main-widget-display-actions": [
{
"name": "Mis entradas",
"command": {
"commandType": "rest",
"method": "GET",
"url": "https://api.example.com/tickets/me",
"header": ["Authorization: Bearer TOKEN"]
},
"responseType": "adaptiveCard",
"adaptiveCardTemplateJsonField": "card",
"adaptiveCardContentJsonField": "data",
"adaptiveCardSubmitUrl": "https://api.example.com/tickets/submit"
}
]
}
}Visualización del marco
Compatible con Rainbow Desktop y Rainbow Web.
Ejemplo 1: «on-main-window-actions» integra un tablero de instrumentos de CRM en el panel principal de Rainbow:
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-main-window-actions": [
{
"name": "Mi CRM",
"icon": "${custo.path}\\crm.png",
"command": {
"url": "https://crm.example.com/dashboard",
"params": "user=${localUser.email}"
}
}
]
}
}Ejemplo 2 — igual que el anterior, pero con `Popup: true` para abrirlo en una ventana del navegador (útil cuando la aplicación no permite la incrustación en iframes):
{
"version": "2",
"jsonType": "Rainbow-custo-manifest",
"extension-points": {
"on-main-window-actions": [
{
"name": "Informes externos",
"icon": "${custo.path}\\report.png",
"Popup": true,
"command": {
"url": "https://reporting.example.com/",
"params": "user=${localUser.loginEmail}"
}
}
]
}
}