359 lines
12 KiB
JavaScript
359 lines
12 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import axios from 'axios';
|
|
import './SettingsWizard.css';
|
|
|
|
function SettingsWizard() {
|
|
const [settings, setSettings] = useState({
|
|
email_enabled: false,
|
|
email_host: 'smtp.gmail.com',
|
|
email_port: 587,
|
|
email_user: '',
|
|
email_pass: '',
|
|
email_from: '',
|
|
email_to: '',
|
|
webhook_enabled: false,
|
|
webhook_url: '',
|
|
check_interval: 60000,
|
|
timeout: 5000,
|
|
timezone: 'UTC',
|
|
});
|
|
|
|
const [testResult, setTestResult] = useState(null);
|
|
const [saving, setSaving] = useState(false);
|
|
const [testing, setTesting] = useState(false);
|
|
|
|
useEffect(() => {
|
|
loadSettings();
|
|
}, []);
|
|
|
|
const loadSettings = async () => {
|
|
try {
|
|
const response = await axios.get('/api/settings');
|
|
setSettings(response.data);
|
|
} catch (error) {
|
|
console.error('Error loading settings:', error);
|
|
}
|
|
};
|
|
|
|
const handleSave = async () => {
|
|
setSaving(true);
|
|
try {
|
|
await axios.post('/api/settings', settings);
|
|
alert('Settings saved successfully! Changes apply immediately.');
|
|
} catch (error) {
|
|
console.error('Error saving settings:', error);
|
|
alert('Error saving settings');
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleTestEmail = async () => {
|
|
setTesting(true);
|
|
setTestResult(null);
|
|
try {
|
|
const response = await axios.post('/api/test-email', {
|
|
email_host: settings.email_host,
|
|
email_port: settings.email_port,
|
|
email_user: settings.email_user,
|
|
email_pass: settings.email_pass,
|
|
email_from: settings.email_from,
|
|
email_to: settings.email_to,
|
|
});
|
|
setTestResult({ success: true, message: response.data.message });
|
|
} catch (error) {
|
|
setTestResult({
|
|
success: false,
|
|
message: error.response?.data?.error || 'Failed to send test email'
|
|
});
|
|
} finally {
|
|
setTesting(false);
|
|
}
|
|
};
|
|
|
|
const handleTestWebhook = async () => {
|
|
setTesting(true);
|
|
setTestResult(null);
|
|
try {
|
|
const response = await axios.post('/api/test-webhook', {
|
|
webhook_url: settings.webhook_url,
|
|
});
|
|
setTestResult({ success: true, message: response.data.message });
|
|
} catch (error) {
|
|
setTestResult({
|
|
success: false,
|
|
message: error.response?.data?.error || 'Failed to send test webhook'
|
|
});
|
|
} finally {
|
|
setTesting(false);
|
|
}
|
|
};
|
|
|
|
const emailProviders = [
|
|
{ name: 'Gmail', host: 'smtp.gmail.com', port: 587 },
|
|
{ name: 'Outlook', host: 'smtp-mail.outlook.com', port: 587 },
|
|
{ name: 'Yahoo', host: 'smtp.mail.yahoo.com', port: 587 },
|
|
{ name: 'Custom', host: '', port: 587 },
|
|
];
|
|
|
|
return (
|
|
<div className="settings-wizard">
|
|
<h2>⚙️ Settings & Notifications</h2>
|
|
<p className="settings-description">
|
|
Configure email and webhook notifications to receive alerts when your resources go offline.
|
|
</p>
|
|
|
|
{/* Email Settings */}
|
|
<div className="settings-section">
|
|
<div className="settings-header">
|
|
<h3>📧 Email Notifications</h3>
|
|
<label className="toggle-switch">
|
|
<input
|
|
type="checkbox"
|
|
checked={settings.email_enabled}
|
|
onChange={(e) => setSettings({ ...settings, email_enabled: e.target.checked })}
|
|
/>
|
|
<span className="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
|
|
{settings.email_enabled && (
|
|
<div className="settings-form">
|
|
<div className="form-row">
|
|
<div className="form-group">
|
|
<label>Email Provider</label>
|
|
<select
|
|
value={emailProviders.find(p => p.host === settings.email_host)?.name || 'Custom'}
|
|
onChange={(e) => {
|
|
const provider = emailProviders.find(p => p.name === e.target.value);
|
|
if (provider) {
|
|
setSettings({
|
|
...settings,
|
|
email_host: provider.host,
|
|
email_port: provider.port,
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
{emailProviders.map(p => (
|
|
<option key={p.name} value={p.name}>{p.name}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>SMTP Host</label>
|
|
<input
|
|
type="text"
|
|
value={settings.email_host}
|
|
onChange={(e) => setSettings({ ...settings, email_host: e.target.value })}
|
|
placeholder="smtp.gmail.com"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>SMTP Port</label>
|
|
<input
|
|
type="number"
|
|
value={settings.email_port}
|
|
onChange={(e) => setSettings({ ...settings, email_port: parseInt(e.target.value) })}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-row">
|
|
<div className="form-group">
|
|
<label>Email Username</label>
|
|
<input
|
|
type="email"
|
|
value={settings.email_user}
|
|
onChange={(e) => setSettings({ ...settings, email_user: e.target.value })}
|
|
placeholder="your-email@gmail.com"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>Email Password / App Password</label>
|
|
<input
|
|
type="password"
|
|
value={settings.email_pass}
|
|
onChange={(e) => setSettings({ ...settings, email_pass: e.target.value })}
|
|
placeholder="your-password-or-app-password"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-row">
|
|
<div className="form-group">
|
|
<label>From Email</label>
|
|
<input
|
|
type="email"
|
|
value={settings.email_from}
|
|
onChange={(e) => setSettings({ ...settings, email_from: e.target.value })}
|
|
placeholder="alerts@example.com"
|
|
/>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>To Email (Alert Recipient)</label>
|
|
<input
|
|
type="email"
|
|
value={settings.email_to}
|
|
onChange={(e) => setSettings({ ...settings, email_to: e.target.value })}
|
|
placeholder="you@example.com"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="info-box">
|
|
<strong>💡 Gmail Setup:</strong>
|
|
<ol>
|
|
<li>Enable 2-factor authentication on your Google account</li>
|
|
<li>Generate an App Password at <a href="https://myaccount.google.com/apppasswords" target="_blank" rel="noopener noreferrer">myaccount.google.com/apppasswords</a></li>
|
|
<li>Use the app password (not your regular password) above</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<button
|
|
className="btn btn-secondary"
|
|
onClick={handleTestEmail}
|
|
disabled={testing || !settings.email_user || !settings.email_pass}
|
|
>
|
|
{testing ? 'Sending...' : '📨 Send Test Email'}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Webhook Settings */}
|
|
<div className="settings-section">
|
|
<div className="settings-header">
|
|
<h3>🔗 Webhook Notifications</h3>
|
|
<label className="toggle-switch">
|
|
<input
|
|
type="checkbox"
|
|
checked={settings.webhook_enabled}
|
|
onChange={(e) => setSettings({ ...settings, webhook_enabled: e.target.checked })}
|
|
/>
|
|
<span className="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
|
|
{settings.webhook_enabled && (
|
|
<div className="settings-form">
|
|
<div className="form-group">
|
|
<label>Webhook URL</label>
|
|
<input
|
|
type="url"
|
|
value={settings.webhook_url}
|
|
onChange={(e) => setSettings({ ...settings, webhook_url: e.target.value })}
|
|
placeholder="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
|
|
/>
|
|
<small>Receives POST requests with incident data when resources go offline/online</small>
|
|
</div>
|
|
|
|
<div className="info-box">
|
|
<strong>💡 Webhook Payload Example:</strong>
|
|
<pre>{JSON.stringify({
|
|
resource: "ZimaOS Server",
|
|
url: "https://example.com",
|
|
status: "down",
|
|
message: "Resource is DOWN",
|
|
timestamp: new Date().toISOString()
|
|
}, null, 2)}</pre>
|
|
</div>
|
|
|
|
<button
|
|
className="btn btn-secondary"
|
|
onClick={handleTestWebhook}
|
|
disabled={testing || !settings.webhook_url}
|
|
>
|
|
{testing ? 'Sending...' : '🔔 Send Test Webhook'}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Test Result */}
|
|
{testResult && (
|
|
<div className={`test-result ${testResult.success ? 'success' : 'error'}`}>
|
|
<strong>{testResult.success ? '✅ Success!' : '❌ Error:'}</strong>
|
|
<p>{testResult.message}</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Monitoring Settings */}
|
|
<div className="settings-section">
|
|
<h3>⏱️ Default Monitoring Settings</h3>
|
|
<div className="settings-form">
|
|
<div className="form-row">
|
|
<div className="form-group">
|
|
<label>Check Interval (milliseconds)</label>
|
|
<input
|
|
type="number"
|
|
value={settings.check_interval}
|
|
onChange={(e) => setSettings({ ...settings, check_interval: parseInt(e.target.value) })}
|
|
min="10000"
|
|
step="1000"
|
|
/>
|
|
<small>Default interval between checks (60000ms = 1 minute)</small>
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
<label>Request Timeout (milliseconds)</label>
|
|
<input
|
|
type="number"
|
|
value={settings.timeout}
|
|
onChange={(e) => setSettings({ ...settings, timeout: parseInt(e.target.value) })}
|
|
min="1000"
|
|
step="1000"
|
|
/>
|
|
<small>How long to wait before considering a request failed</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-row">
|
|
<div className="form-group">
|
|
<label>Timezone</label>
|
|
<select
|
|
value={settings.timezone}
|
|
onChange={(e) => setSettings({ ...settings, timezone: e.target.value })}
|
|
>
|
|
<option value="UTC">UTC</option>
|
|
<option value="America/New_York">America/New_York (EST)</option>
|
|
<option value="America/Chicago">America/Chicago (CST)</option>
|
|
<option value="America/Denver">America/Denver (MST)</option>
|
|
<option value="America/Los_Angeles">America/Los_Angeles (PST)</option>
|
|
<option value="Europe/London">Europe/London (GMT)</option>
|
|
<option value="Europe/Paris">Europe/Paris (CET)</option>
|
|
<option value="Europe/Berlin">Europe/Berlin (CET)</option>
|
|
<option value="Asia/Tokyo">Asia/Tokyo (JST)</option>
|
|
<option value="Asia/Shanghai">Asia/Shanghai (CST)</option>
|
|
<option value="Asia/Hong_Kong">Asia/Hong_Kong (HKT)</option>
|
|
<option value="Asia/Singapore">Asia/Singapore (SGT)</option>
|
|
<option value="Asia/Dubai">Asia/Dubai (GST)</option>
|
|
<option value="Australia/Sydney">Australia/Sydney (AEDT)</option>
|
|
<option value="Australia/Melbourne">Australia/Melbourne (AEDT)</option>
|
|
</select>
|
|
<small>Timezone for timestamps and alerts</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Save Button */}
|
|
<div className="settings-actions">
|
|
<button
|
|
className="btn btn-primary btn-large"
|
|
onClick={handleSave}
|
|
disabled={saving}
|
|
>
|
|
{saving ? 'Saving...' : '💾 Save Settings'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default SettingsWizard;
|