Teams integration: webhook messaging + configuración en Settings + plugin-http

- @tauri-apps/plugin-http instalado (npm + Cargo.toml + capabilities)
- src-tauri/src/main.rs: registrado tauri_plugin_http::init()
- services/teams.ts: servicio para enviar mensajes Teams via webhook
  soporta Tauri plugin y browser fetch con fallback automático
  incluye notifyHUCreated, notifyBlockerLogged, sendTestMessage
- SettingsView: nueva sección Teams con input de webhook URL + botón test
- ChartAreaInteractive.vue: removido import no usado (@unovis/vue)
This commit is contained in:
2026-05-29 23:55:37 -05:00
parent bf81b8e04b
commit b21214d1f1
13 changed files with 6919 additions and 15 deletions
+138
View File
@@ -0,0 +1,138 @@
import { storage } from '@/services/storage'
const STORAGE_KEY = 'teams_webhook_url'
export function getWebhookUrl(): string {
return storage.get(STORAGE_KEY) || ''
}
export function setWebhookUrl(url: string): void {
storage.set(STORAGE_KEY, url)
}
export function hasWebhook(): boolean {
return !!getWebhookUrl()
}
interface TeamsMessage {
title?: string
text: string
themeColor?: string
sections?: {
activityTitle?: string
activitySubtitle?: string
facts?: { name: string; value: string }[]
text?: string
}[]
}
/**
* Envía un mensaje a Teams via webhook.
* Formato: https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook
* Soporta tanto Tauri (plugin-http) como browser (fetch).
*/
export async function sendToTeams(message: TeamsMessage): Promise<boolean> {
const webhookUrl = getWebhookUrl()
if (!webhookUrl) {
console.warn('[Teams] No hay webhook configurado')
return false
}
const payload = {
'@type': 'MessageCard',
'@context': 'http://schema.org/extensions',
summary: message.title || message.text.slice(0, 50),
title: message.title,
text: message.text,
themeColor: message.themeColor || '0078D4',
sections: message.sections || [],
}
try {
// Intentar usar Tauri plugin HTTP primero
if (typeof window !== 'undefined' && (window as any).__TAURI_INTERNALS__) {
const { fetch } = await import('@tauri-apps/plugin-http')
const res = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
if (!res.ok) {
console.error(`[Teams] Error HTTP ${res.status}`)
return false
}
console.log('[Teams] Mensaje enviado via Tauri plugin')
return true
}
// Fallback browser fetch
const res = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
if (!res.ok) {
console.error(`[Teams] Error HTTP ${res.status}`)
return false
}
console.log('[Teams] Mensaje enviado via browser fetch')
return true
} catch (e: any) {
console.error('[Teams] Error al enviar mensaje:', e)
return false
}
}
/**
* Envía una notificación de HU creada.
*/
export async function notifyHUCreated(projectName: string, huTitle: string, huUrl?: string): Promise<boolean> {
return sendToTeams({
title: '🆕 Nueva HU creada',
text: `**Proyecto:** ${projectName}`,
themeColor: '0078D4',
sections: [{
facts: [
{ name: 'HU', value: huTitle },
{ name: 'Proyecto', value: projectName },
{ name: 'URL', value: huUrl || window.location.href },
],
}],
})
}
/**
* Envía una notificación de bloqueo/impedimento.
*/
export async function notifyBlockerLogged(
projectName: string,
huTitle: string,
category: string,
description: string,
hoursLost: number,
): Promise<boolean> {
return sendToTeams({
title: '⛔ Bloqueo registrado',
text: `**Proyecto:** ${projectName}`,
themeColor: 'FF4444',
sections: [{
facts: [
{ name: 'HU', value: huTitle },
{ name: 'Categoría', value: category },
{ name: 'Descripción', value: description },
{ name: 'Horas perdidas', value: `${hoursLost}h` },
],
}],
})
}
/**
* Envía un mensaje de prueba.
*/
export async function sendTestMessage(): Promise<boolean> {
return sendToTeams({
title: '🔔 Prueba de integración',
text: 'Este es un mensaje de prueba desde **Alpha**.\n\nSi ves esto, la integración con Teams funciona correctamente.',
themeColor: '00FF00',
})
}