Fix bugs, UX rough edges, add ntfy.sh + network discovery
Bugs fixed: - Status page: autoRefresh checkbox now actually pauses the interval - Dashboard edit modal: hide URL field for heartbeat resources (was always shown as required) - Dashboard: apply items_per_page, default_sort, and refresh_interval from settings on mount - Dashboard: call loadResources() immediately on mount (was waiting 15s for fallback) - Observability: listen for WS 'metrics' messages so tab updates live, not just on poll UX improvements: - Dashboard: replaced window.confirm() with inline Confirm/Cancel buttons for single and bulk delete - Dashboard: skeleton rows shown while initial data loads (no more flash of empty state) - Notifications: WebSocket moved from window global to useRef; exponential backoff on reconnect - Notifications: replaced window.confirm() with inline Confirm/Cancel for Clear All - ResourceDetail: initial API calls run in parallel via Promise.all New features: - ntfy.sh push notification channel: enable in Settings, enter topic, get mobile push alerts - Network Discovery: Actions → Discover Network scans LAN for reachable hosts, probes HTTP ports, and lets you add any found host to monitoring in one click Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
de4619992e
commit
8d50d3cb61
21 files changed
+668
-105
No files matched your search
@@ -21,12 +21,16 @@ class NotificationService {
|
||||
webhook_enabled: process.env.WEBHOOK_ENABLED === 'true',
|
||||
webhook_url: process.env.WEBHOOK_URL,
|
||||
webhook_template: process.env.WEBHOOK_TEMPLATE || '',
|
||||
ntfy_enabled: process.env.NTFY_ENABLED === 'true',
|
||||
ntfy_url: process.env.NTFY_URL || 'https://ntfy.sh',
|
||||
ntfy_topic: process.env.NTFY_TOPIC || '',
|
||||
});
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
this.emailEnabled = !!config.email_enabled;
|
||||
this.webhookEnabled = !!config.webhook_enabled;
|
||||
this.ntfyEnabled = !!config.ntfy_enabled;
|
||||
this.config = { ...this.config, ...config };
|
||||
|
||||
// Recreate transporter when email config changes; skip if incomplete
|
||||
@@ -103,6 +107,10 @@ class NotificationService {
|
||||
promises.push(this.sendWebhook(resource, message, incident.type));
|
||||
}
|
||||
|
||||
if (this.ntfyEnabled) {
|
||||
promises.push(this.sendNtfy(resource, incident.type));
|
||||
}
|
||||
|
||||
await Promise.allSettled(promises);
|
||||
|
||||
// Save notification to in-app notification center
|
||||
@@ -166,6 +174,20 @@ class NotificationService {
|
||||
if (this.webhookEnabled) {
|
||||
await this.sendGroupedWebhook(pendingAlerts);
|
||||
}
|
||||
if (this.ntfyEnabled) {
|
||||
const ntfyUrl = this.config.ntfy_url || 'https://ntfy.sh';
|
||||
const ntfyTopic = this.config.ntfy_topic;
|
||||
if (ntfyTopic) {
|
||||
try {
|
||||
await axios.post(`${ntfyUrl.replace(/\/$/, '')}/${ntfyTopic}`,
|
||||
pendingAlerts.map(({ resource, incident }) =>
|
||||
`${incident.type === 'started' ? '🔴' : '🟢'} ${resource.name}`
|
||||
).join('\n'),
|
||||
{ headers: { Title: `⚠️ ${pendingAlerts.length} monitors changed`, Priority: 'high', Tags: 'warning' } }
|
||||
);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async sendGroupedEmail(alerts) {
|
||||
@@ -420,6 +442,31 @@ class NotificationService {
|
||||
// Webhook error handled silently
|
||||
}
|
||||
}
|
||||
|
||||
async sendNtfy(resource, type) {
|
||||
const ntfyUrl = this.config.ntfy_url || 'https://ntfy.sh';
|
||||
const ntfyTopic = this.config.ntfy_topic;
|
||||
if (!ntfyTopic) return;
|
||||
|
||||
const isDown = type === 'started';
|
||||
const isSlow = type === 'slow';
|
||||
const title = isDown ? `🔴 ${resource.name} is DOWN` : isSlow ? `🟡 ${resource.name} is SLOW` : `🟢 ${resource.name} is UP`;
|
||||
const priority = isDown ? 'high' : isSlow ? 'default' : 'low';
|
||||
const tags = isDown ? 'red_circle,warning' : isSlow ? 'yellow_circle' : 'green_circle,white_check_mark';
|
||||
const body = resource.url ? `${resource.url}` : resource.name;
|
||||
|
||||
try {
|
||||
await axios.post(`${ntfyUrl.replace(/\/$/, '')}/${ntfyTopic}`, body, {
|
||||
headers: {
|
||||
Title: title,
|
||||
Priority: priority,
|
||||
Tags: tags,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// ntfy error handled silently
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new NotificationService();
|
||||
Reference in new issue
Block a user