feat: add 7 new features — exec shell, SSE events, compose import, docker resources, resource limits, email notifications, auto-updates
- Container exec/shell via WebSocket + xterm.js (subtle >_ button on cards) - Live dashboard updates via SSE (resource alerts, health changes, update notices) - Docker Compose import with YAML parsing, preview, and dependency-ordered deploy - Volume & network management modal with disk usage overview - CPU/memory resource limits on deploy and live update - Email SMTP notifications (nodemailer) alongside Discord/Telegram/ntfy - Scheduled auto-update scheduler with maintenance windows (daily/weekly/monthly) New deps: ws, js-yaml, nodemailer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const express = require('express');
|
||||
const { validateURL, validateToken } = require('../input-validator');
|
||||
const validatorLib = require('validator');
|
||||
const { paginate, parsePaginationParams } = require('../pagination');
|
||||
const { ValidationError } = require('../errors');
|
||||
|
||||
@@ -32,6 +33,12 @@ module.exports = function({ notification, asyncHandler }) {
|
||||
enabled: notificationConfig.providers.ntfy?.enabled || false,
|
||||
configured: !!notificationConfig.providers.ntfy?.topic,
|
||||
serverUrl: notificationConfig.providers.ntfy?.serverUrl || 'https://ntfy.sh'
|
||||
},
|
||||
email: {
|
||||
enabled: notificationConfig.providers.email?.enabled || false,
|
||||
configured: !!(notificationConfig.providers.email?.host && notificationConfig.providers.email?.to),
|
||||
host: notificationConfig.providers.email?.host || '',
|
||||
from: notificationConfig.providers.email?.from || ''
|
||||
}
|
||||
},
|
||||
events: notificationConfig.events,
|
||||
@@ -74,6 +81,19 @@ module.exports = function({ notification, asyncHandler }) {
|
||||
throw new ValidationError('Invalid ntfy topic (alphanumeric, hyphens, underscores only, max 64 chars)');
|
||||
}
|
||||
}
|
||||
if (providers.email?.to) {
|
||||
const emails = providers.email.to.split(',').map(e => e.trim());
|
||||
for (const email of emails) {
|
||||
if (!validatorLib.isEmail(email)) {
|
||||
throw new ValidationError(`Invalid email address: ${email}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (providers.email?.host && typeof providers.email.host === 'string') {
|
||||
if (!validatorLib.isFQDN(providers.email.host) && !validatorLib.isIP(providers.email.host)) {
|
||||
throw new ValidationError('Invalid SMTP host');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update enabled state
|
||||
@@ -101,6 +121,12 @@ module.exports = function({ notification, asyncHandler }) {
|
||||
...providers.ntfy
|
||||
};
|
||||
}
|
||||
if (providers.email) {
|
||||
notificationConfig.providers.email = {
|
||||
...notificationConfig.providers.email,
|
||||
...providers.email
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Update events
|
||||
@@ -144,6 +170,9 @@ module.exports = function({ notification, asyncHandler }) {
|
||||
case 'ntfy':
|
||||
result = await notification.sendNtfy('Test Notification', 'This is a test notification from DashCaddy.', 'info');
|
||||
break;
|
||||
case 'email':
|
||||
result = await notification.sendEmail('Test Notification', 'This is a test notification from DashCaddy.', 'info');
|
||||
break;
|
||||
default:
|
||||
throw new ValidationError('Unknown provider');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user