mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-06 00:47:52 +00:00
c6eb9d76e7
- Implemented NotificationSettingsModal for configuring notification agents (Discord, Slack, Webhook) and global settings. - Added StackAlertSheet for managing stack-specific alert rules with metrics, thresholds, and cooldowns. - Introduced reusable UI components: DropdownMenu, Popover, Select, Sheet, Slider, and Switch. - Enhanced Tabs component by removing unnecessary client directive.
130 lines
4.1 KiB
TypeScript
130 lines
4.1 KiB
TypeScript
import { DatabaseService } from './DatabaseService';
|
||
|
||
export class NotificationService {
|
||
private static instance: NotificationService;
|
||
private dbService: DatabaseService;
|
||
|
||
private constructor() {
|
||
this.dbService = DatabaseService.getInstance();
|
||
}
|
||
|
||
public static getInstance(): NotificationService {
|
||
if (!NotificationService.instance) {
|
||
NotificationService.instance = new NotificationService();
|
||
}
|
||
return NotificationService.instance;
|
||
}
|
||
|
||
public async dispatchAlert(level: 'info' | 'warning' | 'error', message: string) {
|
||
// 1. Log to history
|
||
this.dbService.addNotificationHistory({
|
||
level,
|
||
message,
|
||
timestamp: Date.now()
|
||
});
|
||
|
||
// 2. Fetch enabled agents
|
||
const agents = this.dbService.getEnabledAgents();
|
||
if (agents.length === 0) {
|
||
console.log('No active notification agents found. Skipping external dispatch.');
|
||
return;
|
||
}
|
||
|
||
// 3. Dispatch to each agent
|
||
for (const agent of agents) {
|
||
try {
|
||
if (agent.type === 'discord') {
|
||
await this.sendDiscordWebhook(agent.url, level, message);
|
||
} else if (agent.type === 'slack') {
|
||
await this.sendSlackWebhook(agent.url, level, message);
|
||
} else if (agent.type === 'webhook') {
|
||
await this.sendCustomWebhook(agent.url, level, message);
|
||
}
|
||
} catch (error) {
|
||
console.error(`Failed to dispatch notification to ${agent.type}:`, error);
|
||
}
|
||
}
|
||
}
|
||
|
||
public async testDispatch(type: 'discord' | 'slack' | 'webhook', url: string) {
|
||
const level = 'info';
|
||
const message = '🔌 Test Notification from Sencho!';
|
||
|
||
if (type === 'discord') {
|
||
await this.sendDiscordWebhook(url, level, message);
|
||
} else if (type === 'slack') {
|
||
await this.sendSlackWebhook(url, level, message);
|
||
} else if (type === 'webhook') {
|
||
await this.sendCustomWebhook(url, level, message);
|
||
}
|
||
}
|
||
|
||
private async sendDiscordWebhook(url: string, level: 'info' | 'warning' | 'error', message: string) {
|
||
const colorMap = {
|
||
info: 3447003, // Blue
|
||
warning: 16776960, // Yellow
|
||
error: 15158332 // Red
|
||
};
|
||
|
||
const payload = {
|
||
embeds: [{
|
||
title: `Sencho Alert [${level.toUpperCase()}]`,
|
||
description: message,
|
||
color: colorMap[level],
|
||
timestamp: new Date().toISOString()
|
||
}]
|
||
};
|
||
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`Discord Webhook responded with ${response.status}`);
|
||
}
|
||
}
|
||
|
||
private async sendSlackWebhook(url: string, level: 'info' | 'warning' | 'error', message: string) {
|
||
const emojiMap = {
|
||
info: 'ℹ️',
|
||
warning: '⚠️',
|
||
error: '🚨'
|
||
};
|
||
|
||
const payload = {
|
||
text: `${emojiMap[level]} *Sencho Alert [${level.toUpperCase()}]*\n${message}`
|
||
};
|
||
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`Slack Webhook responded with ${response.status}`);
|
||
}
|
||
}
|
||
|
||
private async sendCustomWebhook(url: string, level: 'info' | 'warning' | 'error', message: string) {
|
||
const payload = {
|
||
level,
|
||
message,
|
||
timestamp: new Date().toISOString(),
|
||
source: 'sencho'
|
||
};
|
||
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`Custom Webhook responded with ${response.status}`);
|
||
}
|
||
}
|
||
}
|