mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
feat(notifications): add ntfy as a first-class notification channel
Adds ntfy.sh (and self-hosted instances) as a new push notification channel with full parity to the existing webhook channel. - Backend: NtfyConfig type, getUserNtfyConfig, getAdminNtfyConfig, resolveNtfyUrl, sendNtfy (header-based API with Title/Priority/Tags/ Click headers), testNtfy, NTFY_EVENT_META (priority + emoji tags per event), SSRF guard via existing checkSsrf + createPinnedDispatcher - notificationPreferencesService: ntfy added to NotifChannel union, IMPLEMENTED_COMBOS, getActiveChannels parser, getAvailableChannels, ADMIN_GLOBAL_CHANNELS, and AvailableChannels interface - notificationService: per-user ntfy dispatch after webhook block; admin-scoped ntfy via getAdminGlobalPref for version_available events - Routes: POST /api/notifications/test-ntfy with saved-token fallback - authService: admin_ntfy_server/topic/token in ADMIN_SETTINGS_KEYS, masked + encrypted on read/write - settingsService: ntfy_token added to ENCRYPTED_SETTING_KEYS - Frontend: ntfy topic/server/token inputs + Save/Test/Clear buttons in NotificationsTab; admin Ntfy panel in AdminPage; testNtfy API method - i18n: full English strings; English placeholders in 14 other locales - Tests: resolveNtfyUrl, sendNtfy, dispatch integration, UI tests, MSW handler for test-ntfy endpoint
This commit is contained in:
@@ -486,6 +486,7 @@ export const notificationsApi = {
|
||||
updatePreferences: (prefs: Record<string, Record<string, boolean>>) => apiClient.put('/notifications/preferences', prefs).then(r => r.data),
|
||||
testSmtp: (email?: string) => apiClient.post('/notifications/test-smtp', { email }).then(r => r.data),
|
||||
testWebhook: (url?: string) => apiClient.post('/notifications/test-webhook', { url }).then(r => r.data),
|
||||
testNtfy: (payload: { topic?: string; server?: string | null; token?: string | null }) => apiClient.post('/notifications/test-ntfy', payload).then(r => r.data),
|
||||
}
|
||||
|
||||
export const inAppNotificationsApi = {
|
||||
|
||||
@@ -347,6 +347,99 @@ describe('NotificationsTab', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('FE-COMP-NOTIFICATIONS-ntfy-001: ntfy topic input renders when ntfy channel is available', async () => {
|
||||
server.use(
|
||||
http.get('/api/notifications/preferences', () =>
|
||||
HttpResponse.json({
|
||||
preferences: { trip_invite: { inapp: true, ntfy: false } },
|
||||
available_channels: { email: false, webhook: false, inapp: true, ntfy: true },
|
||||
event_types: ['trip_invite'],
|
||||
implemented_combos: { trip_invite: ['inapp', 'ntfy'] },
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
render(<NotificationsTab />);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Ntfy topic input should be present (placeholder text from i18n key or EN default)
|
||||
const inputs = await screen.findAllByRole('textbox');
|
||||
expect(inputs.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('FE-COMP-NOTIFICATIONS-ntfy-002: ntfy test button disabled when no topic entered', async () => {
|
||||
server.use(
|
||||
http.get('/api/notifications/preferences', () =>
|
||||
HttpResponse.json({
|
||||
preferences: { trip_invite: { inapp: true, ntfy: false } },
|
||||
available_channels: { email: false, webhook: false, inapp: true, ntfy: true },
|
||||
event_types: ['trip_invite'],
|
||||
implemented_combos: { trip_invite: ['inapp', 'ntfy'] },
|
||||
}),
|
||||
),
|
||||
http.get('/api/settings', () => HttpResponse.json({ settings: { ntfy_topic: '' } })),
|
||||
);
|
||||
|
||||
render(<NotificationsTab />);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Test button should be disabled when topic is empty
|
||||
const allButtons = await screen.findAllByRole('button');
|
||||
const testBtn = allButtons.find(b => /test/i.test(b.textContent || ''));
|
||||
expect(testBtn).toBeDefined();
|
||||
expect(testBtn).toBeDisabled();
|
||||
});
|
||||
|
||||
it('FE-COMP-NOTIFICATIONS-ntfy-003: entering topic and clicking Test calls test-ntfy API', async () => {
|
||||
const user = userEvent.setup();
|
||||
let ntfyCalled = false;
|
||||
server.use(
|
||||
http.get('/api/notifications/preferences', () =>
|
||||
HttpResponse.json({
|
||||
preferences: { trip_invite: { inapp: true, ntfy: false } },
|
||||
available_channels: { email: false, webhook: false, inapp: true, ntfy: true },
|
||||
event_types: ['trip_invite'],
|
||||
implemented_combos: { trip_invite: ['inapp', 'ntfy'] },
|
||||
}),
|
||||
),
|
||||
http.post('/api/notifications/test-ntfy', () => {
|
||||
ntfyCalled = true;
|
||||
return HttpResponse.json({ success: true });
|
||||
}),
|
||||
);
|
||||
|
||||
render(
|
||||
<>
|
||||
<NotificationsTab />
|
||||
<ToastContainer />
|
||||
</>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Find the topic input (first textbox in the ntfy block) and type a topic
|
||||
const inputs = await screen.findAllByRole('textbox');
|
||||
await user.type(inputs[0], 'my-test-topic');
|
||||
|
||||
// Test button should now be enabled
|
||||
const allButtons = screen.getAllByRole('button');
|
||||
const testBtn = allButtons.find(b => /test/i.test(b.textContent || ''));
|
||||
expect(testBtn).toBeDefined();
|
||||
expect(testBtn).not.toBeDisabled();
|
||||
|
||||
await user.click(testBtn!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(ntfyCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('FE-COMP-NOTIFICATIONS-014: failed test webhook shows error toast with message', async () => {
|
||||
const user = userEvent.setup();
|
||||
server.use(
|
||||
|
||||
@@ -8,7 +8,7 @@ import Section from './Section'
|
||||
|
||||
interface PreferencesMatrix {
|
||||
preferences: Record<string, Record<string, boolean>>
|
||||
available_channels: { email: boolean; webhook: boolean; inapp: boolean }
|
||||
available_channels: { email: boolean; webhook: boolean; inapp: boolean; ntfy: boolean }
|
||||
event_types: string[]
|
||||
implemented_combos: Record<string, string[]>
|
||||
}
|
||||
@@ -17,6 +17,7 @@ const CHANNEL_LABEL_KEYS: Record<string, string> = {
|
||||
email: 'settings.notificationPreferences.email',
|
||||
webhook: 'settings.notificationPreferences.webhook',
|
||||
inapp: 'settings.notificationPreferences.inapp',
|
||||
ntfy: 'settings.notificationPreferences.ntfy',
|
||||
}
|
||||
|
||||
const EVENT_LABEL_KEYS: Record<string, string> = {
|
||||
@@ -39,6 +40,12 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
const [webhookIsSet, setWebhookIsSet] = useState(false)
|
||||
const [webhookSaving, setWebhookSaving] = useState(false)
|
||||
const [webhookTesting, setWebhookTesting] = useState(false)
|
||||
const [ntfyTopic, setNtfyTopic] = useState('')
|
||||
const [ntfyServer, setNtfyServer] = useState('')
|
||||
const [ntfyToken, setNtfyToken] = useState('')
|
||||
const [ntfyTokenIsSet, setNtfyTokenIsSet] = useState(false)
|
||||
const [ntfySaving, setNtfySaving] = useState(false)
|
||||
const [ntfyTesting, setNtfyTesting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
notificationsApi.getPreferences().then((data: PreferencesMatrix) => setMatrix(data)).catch(() => {})
|
||||
@@ -50,12 +57,21 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
} else {
|
||||
setWebhookUrl(val)
|
||||
}
|
||||
setNtfyTopic((data.settings?.ntfy_topic as string) || '')
|
||||
setNtfyServer((data.settings?.ntfy_server as string) || '')
|
||||
const rawToken = (data.settings?.ntfy_token as string) || ''
|
||||
if (rawToken === '••••••••') {
|
||||
setNtfyTokenIsSet(true)
|
||||
setNtfyToken('')
|
||||
} else {
|
||||
setNtfyToken(rawToken)
|
||||
}
|
||||
}).catch(() => {})
|
||||
}, [])
|
||||
|
||||
const visibleChannels = matrix
|
||||
? (['email', 'webhook', 'inapp'] as const).filter(ch => {
|
||||
if (!matrix.available_channels[ch]) return false
|
||||
? (['email', 'webhook', 'ntfy', 'inapp'] as const).filter(ch => {
|
||||
if (!matrix.available_channels[ch as keyof typeof matrix.available_channels]) return false
|
||||
return matrix.event_types.some(evt => matrix.implemented_combos[evt]?.includes(ch))
|
||||
})
|
||||
: []
|
||||
@@ -106,6 +122,52 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
const saveNtfySettings = async () => {
|
||||
setNtfySaving(true)
|
||||
try {
|
||||
await settingsApi.setBulk({
|
||||
ntfy_topic: ntfyTopic,
|
||||
ntfy_server: ntfyServer,
|
||||
...(ntfyToken && ntfyToken !== '••••••••' ? { ntfy_token: ntfyToken } : {}),
|
||||
})
|
||||
if (ntfyToken && ntfyToken !== '••••••••') setNtfyTokenIsSet(true)
|
||||
toast.success(t('settings.ntfyUrl.saved'))
|
||||
} catch {
|
||||
toast.error(t('common.error'))
|
||||
} finally {
|
||||
setNtfySaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
const clearNtfyToken = async () => {
|
||||
try {
|
||||
await settingsApi.set('ntfy_token', '')
|
||||
setNtfyToken('')
|
||||
setNtfyTokenIsSet(false)
|
||||
toast.success(t('settings.ntfyUrl.tokenCleared'))
|
||||
} catch {
|
||||
toast.error(t('common.error'))
|
||||
}
|
||||
}
|
||||
|
||||
const testNtfySettings = async () => {
|
||||
if (!ntfyTopic) return
|
||||
setNtfyTesting(true)
|
||||
try {
|
||||
const result = await notificationsApi.testNtfy({
|
||||
topic: ntfyTopic,
|
||||
server: ntfyServer || null,
|
||||
token: ntfyToken && ntfyToken !== '••••••••' ? ntfyToken : null,
|
||||
})
|
||||
if (result.success) toast.success(t('settings.ntfyUrl.testSuccess'))
|
||||
else toast.error(result.error || t('settings.ntfyUrl.testFailed'))
|
||||
} catch {
|
||||
toast.error(t('settings.ntfyUrl.testFailed'))
|
||||
} finally {
|
||||
setNtfyTesting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const renderContent = () => {
|
||||
if (!matrix) return <p style={{ fontSize: 12, color: 'var(--text-faint)', fontStyle: 'italic' }}>{t('common.loading')}</p>
|
||||
|
||||
@@ -139,7 +201,7 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
disabled={webhookSaving}
|
||||
style={{ fontSize: 12, padding: '6px 12px', background: 'var(--text-primary)', color: 'var(--bg-primary)', border: 'none', borderRadius: 6, cursor: webhookSaving ? 'not-allowed' : 'pointer', opacity: webhookSaving ? 0.6 : 1 }}
|
||||
>
|
||||
{t('settings.webhookUrl.save')}
|
||||
{t('common.save')}
|
||||
</button>
|
||||
<button
|
||||
onClick={testWebhookUrl}
|
||||
@@ -151,6 +213,66 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{matrix.available_channels.ntfy && (
|
||||
<div style={{ marginBottom: 16, padding: '12px', background: 'var(--bg-secondary)', borderRadius: 8, border: '1px solid var(--border-primary)' }}>
|
||||
<label style={{ display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 4 }}>
|
||||
{t('settings.ntfyUrl.topicLabel')}
|
||||
</label>
|
||||
<p style={{ fontSize: 11, color: 'var(--text-faint)', marginBottom: 8 }}>{t('settings.ntfyUrl.hint')}</p>
|
||||
<input
|
||||
type="text"
|
||||
value={ntfyTopic}
|
||||
onChange={e => setNtfyTopic(e.target.value)}
|
||||
placeholder={t('settings.ntfyUrl.topicPlaceholder')}
|
||||
style={{ width: '100%', boxSizing: 'border-box', fontSize: 13, padding: '6px 10px', border: '1px solid var(--border-primary)', borderRadius: 6, background: 'var(--bg-primary)', color: 'var(--text-primary)', marginBottom: 6 }}
|
||||
/>
|
||||
<label style={{ display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 4 }}>
|
||||
{t('settings.ntfyUrl.serverLabel')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={ntfyServer}
|
||||
onChange={e => setNtfyServer(e.target.value)}
|
||||
placeholder={t('settings.ntfyUrl.serverPlaceholder')}
|
||||
style={{ width: '100%', boxSizing: 'border-box', fontSize: 13, padding: '6px 10px', border: '1px solid var(--border-primary)', borderRadius: 6, background: 'var(--bg-primary)', color: 'var(--text-primary)', marginBottom: 6 }}
|
||||
/>
|
||||
<label style={{ display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 4 }}>
|
||||
{t('settings.ntfyUrl.tokenLabel')}
|
||||
</label>
|
||||
<p style={{ fontSize: 11, color: 'var(--text-faint)', marginBottom: 4 }}>{t('settings.ntfyUrl.tokenHint')}</p>
|
||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
<input
|
||||
type="password"
|
||||
value={ntfyToken}
|
||||
onChange={e => setNtfyToken(e.target.value)}
|
||||
placeholder={ntfyTokenIsSet ? '••••••••' : ''}
|
||||
style={{ flex: 1, fontSize: 13, padding: '6px 10px', border: '1px solid var(--border-primary)', borderRadius: 6, background: 'var(--bg-primary)', color: 'var(--text-primary)' }}
|
||||
/>
|
||||
{ntfyTokenIsSet && (
|
||||
<button
|
||||
onClick={clearNtfyToken}
|
||||
style={{ fontSize: 12, padding: '6px 12px', background: 'transparent', color: 'var(--color-danger, #e53e3e)', border: '1px solid var(--color-danger, #e53e3e)', borderRadius: 6, cursor: 'pointer' }}
|
||||
>
|
||||
{t('settings.ntfyUrl.clearToken')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={saveNtfySettings}
|
||||
disabled={ntfySaving}
|
||||
style={{ fontSize: 12, padding: '6px 12px', background: 'var(--text-primary)', color: 'var(--bg-primary)', border: 'none', borderRadius: 6, cursor: ntfySaving ? 'not-allowed' : 'pointer', opacity: ntfySaving ? 0.6 : 1 }}
|
||||
>
|
||||
{t('common.save')}
|
||||
</button>
|
||||
<button
|
||||
onClick={testNtfySettings}
|
||||
disabled={!ntfyTopic || ntfyTesting}
|
||||
style={{ fontSize: 12, padding: '6px 12px', background: 'transparent', color: 'var(--text-secondary)', border: '1px solid var(--border-primary)', borderRadius: 6, cursor: (!ntfyTopic || ntfyTesting) ? 'not-allowed' : 'pointer', opacity: (!ntfyTopic || ntfyTesting) ? 0.5 : 1 }}
|
||||
>
|
||||
{t('settings.ntfyUrl.test')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* Header row */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: `1fr ${visibleChannels.map(() => '64px').join(' ')}`, gap: 4, paddingBottom: 6, marginBottom: 4, borderBottom: '1px solid var(--border-primary)' }}>
|
||||
<span />
|
||||
|
||||
@@ -1809,14 +1809,27 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'رابط Webhook',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'أدخل رابط Webhook الخاص بـ Discord أو Slack أو المخصص لتلقي الإشعارات.',
|
||||
'settings.webhookUrl.save': 'حفظ',
|
||||
'settings.webhookUrl.saved': 'تم حفظ رابط Webhook',
|
||||
'settings.webhookUrl.test': 'اختبار',
|
||||
'settings.webhookUrl.testSuccess': 'تم إرسال Webhook الاختباري بنجاح',
|
||||
'settings.webhookUrl.testFailed': 'فشل إرسال Webhook الاختباري',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1827,6 +1840,22 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'تم إرسال Webhook الاختباري بنجاح',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'فشل إرسال Webhook الاختباري',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'يُرسل Webhook المسؤول تلقائيًا عند تعيين رابط URL',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'حدد القنوات التي تُسلّم إشعارات المسؤول (مثل تنبيهات الإصدارات). يُرسل الـ Webhook تلقائيًا عند تعيين رابط URL لـ Webhook المسؤول.',
|
||||
'admin.tabs.notifications': 'الإشعارات',
|
||||
'notifications.versionAvailable.title': 'تحديث متاح',
|
||||
|
||||
@@ -1758,14 +1758,27 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'URL do webhook',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Insira a URL do seu webhook do Discord, Slack ou personalizado para receber notificações.',
|
||||
'settings.webhookUrl.save': 'Salvar',
|
||||
'settings.webhookUrl.saved': 'URL do webhook salva',
|
||||
'settings.webhookUrl.test': 'Testar',
|
||||
'settings.webhookUrl.testSuccess': 'Webhook de teste enviado com sucesso',
|
||||
'settings.webhookUrl.testFailed': 'Falha no webhook de teste',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1776,6 +1789,22 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Webhook de teste enviado com sucesso',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Falha no webhook de teste',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'O webhook de admin dispara automaticamente quando uma URL está configurada',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Configure quais canais entregam notificações de admin (ex. alertas de versão). O webhook dispara automaticamente se uma URL de webhook de admin estiver definida.',
|
||||
'admin.tabs.notifications': 'Notificações',
|
||||
'notifications.versionAvailable.title': 'Atualização disponível',
|
||||
|
||||
@@ -1763,14 +1763,27 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'URL webhooku',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Zadejte URL vašeho Discord, Slack nebo vlastního webhooku pro příjem oznámení.',
|
||||
'settings.webhookUrl.save': 'Uložit',
|
||||
'settings.webhookUrl.saved': 'URL webhooku uložena',
|
||||
'settings.webhookUrl.test': 'Otestovat',
|
||||
'settings.webhookUrl.testSuccess': 'Testovací webhook byl úspěšně odeslán',
|
||||
'settings.webhookUrl.testFailed': 'Testovací webhook selhal',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1781,6 +1794,22 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Testovací webhook byl úspěšně odeslán',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Testovací webhook selhal',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Admin webhook odesílá automaticky, pokud je nastavena URL',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Nastavte, které kanály doručují admin oznámení (např. upozornění na verze). Webhook odesílá automaticky, pokud je nastavena URL admin webhooku.',
|
||||
'admin.tabs.notifications': 'Oznámení',
|
||||
'notifications.versionAvailable.title': 'Dostupná aktualizace',
|
||||
|
||||
@@ -1766,14 +1766,27 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'Webhook-URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Gib deine Discord-, Slack- oder benutzerdefinierte Webhook-URL ein, um Benachrichtigungen zu erhalten.',
|
||||
'settings.webhookUrl.save': 'Speichern',
|
||||
'settings.webhookUrl.saved': 'Webhook-URL gespeichert',
|
||||
'settings.webhookUrl.test': 'Testen',
|
||||
'settings.webhookUrl.testSuccess': 'Test-Webhook erfolgreich gesendet',
|
||||
'settings.webhookUrl.testFailed': 'Test-Webhook fehlgeschlagen',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1784,6 +1797,22 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Test-Webhook erfolgreich gesendet',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Test-Webhook fehlgeschlagen',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Admin-Webhook sendet automatisch, wenn eine URL konfiguriert ist',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Konfiguriere, welche Kanäle Admin-Benachrichtigungen liefern (z. B. Versions-Updates). Der Webhook sendet automatisch, wenn eine Admin-Webhook-URL gesetzt ist.',
|
||||
'admin.tabs.notifications': 'Benachrichtigungen',
|
||||
'notifications.versionAvailable.title': 'Update verfügbar',
|
||||
|
||||
@@ -189,25 +189,42 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'settings.notificationPreferences.noChannels': 'No notification channels are configured. Ask an admin to set up email or webhook notifications.',
|
||||
'settings.webhookUrl.label': 'Webhook URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Enter your Discord, Slack, or custom webhook URL to receive notifications.',
|
||||
'settings.webhookUrl.save': 'Save',
|
||||
'settings.webhookUrl.saved': 'Webhook URL saved',
|
||||
'settings.webhookUrl.test': 'Test',
|
||||
'settings.webhookUrl.testSuccess': 'Test webhook sent successfully',
|
||||
'settings.webhookUrl.testFailed': 'Test webhook failed',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'admin.notifications.title': 'Notifications',
|
||||
'admin.notifications.hint': 'Choose one notification channel. Only one can be active at a time.',
|
||||
'admin.notifications.none': 'Disabled',
|
||||
'admin.notifications.email': 'Email (SMTP)',
|
||||
'admin.notifications.webhook': 'Webhook',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.save': 'Save notification settings',
|
||||
'admin.notifications.saved': 'Notification settings saved',
|
||||
'admin.notifications.testWebhook': 'Send test webhook',
|
||||
'admin.notifications.testWebhookSuccess': 'Test webhook sent successfully',
|
||||
'admin.notifications.testWebhookFailed': 'Test webhook failed',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -218,6 +235,18 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Test webhook sent successfully',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Test webhook failed',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Admin webhook always fires when a URL is configured',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Configure which channels deliver admin-only notifications (e.g. version alerts).',
|
||||
'admin.smtp.title': 'Email & Notifications',
|
||||
'admin.smtp.hint': 'SMTP configuration for sending email notifications.',
|
||||
|
||||
@@ -1768,14 +1768,27 @@ const es: Record<string, string> = {
|
||||
'settings.webhookUrl.label': 'URL del webhook',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Introduce tu URL de webhook de Discord, Slack o personalizada para recibir notificaciones.',
|
||||
'settings.webhookUrl.save': 'Guardar',
|
||||
'settings.webhookUrl.saved': 'URL del webhook guardada',
|
||||
'settings.webhookUrl.test': 'Probar',
|
||||
'settings.webhookUrl.testSuccess': 'Webhook de prueba enviado correctamente',
|
||||
'settings.webhookUrl.testFailed': 'Error al enviar el webhook de prueba',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1786,6 +1799,22 @@ const es: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Webhook de prueba enviado correctamente',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Error al enviar el webhook de prueba',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'El webhook de admin se activa automáticamente si hay una URL configurada',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Configura qué canales entregan notificaciones de admin (ej. alertas de versión). El webhook se activa automáticamente si hay una URL de webhook de admin configurada.',
|
||||
'admin.tabs.notifications': 'Notificaciones',
|
||||
'notifications.versionAvailable.title': 'Actualización disponible',
|
||||
|
||||
@@ -1762,14 +1762,27 @@ const fr: Record<string, string> = {
|
||||
'settings.webhookUrl.label': 'URL du webhook',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Entrez votre URL de webhook Discord, Slack ou personnalisée pour recevoir des notifications.',
|
||||
'settings.webhookUrl.save': 'Enregistrer',
|
||||
'settings.webhookUrl.saved': 'URL du webhook enregistrée',
|
||||
'settings.webhookUrl.test': 'Tester',
|
||||
'settings.webhookUrl.testSuccess': 'Webhook de test envoyé avec succès',
|
||||
'settings.webhookUrl.testFailed': 'Échec du webhook de test',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1780,6 +1793,22 @@ const fr: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Webhook de test envoyé avec succès',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Échec du webhook de test',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Le webhook admin s\'active automatiquement si une URL est configurée',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Configurez quels canaux envoient les notifications admin (ex. alertes de version). Le webhook s\'active automatiquement si une URL webhook admin est définie.',
|
||||
'admin.tabs.notifications': 'Notifications',
|
||||
'notifications.versionAvailable.title': 'Mise à jour disponible',
|
||||
|
||||
@@ -1760,14 +1760,27 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'Webhook URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Adja meg a Discord, Slack vagy egyéni webhook URL-jét az értesítések fogadásához.',
|
||||
'settings.webhookUrl.save': 'Mentés',
|
||||
'settings.webhookUrl.saved': 'Webhook URL mentve',
|
||||
'settings.webhookUrl.test': 'Teszt',
|
||||
'settings.webhookUrl.testSuccess': 'Teszt webhook sikeresen elküldve',
|
||||
'settings.webhookUrl.testFailed': 'Teszt webhook sikertelen',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1778,6 +1791,22 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Teszt webhook sikeresen elküldve',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Teszt webhook sikertelen',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Az admin webhook automatikusan küld, ha URL van beállítva',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Állítsa be, hogy mely csatornák szállítsák az admin értesítéseket (pl. verziófrissítési figyelmeztetések). A webhook automatikusan küld, ha admin webhook URL van megadva.',
|
||||
'admin.tabs.notifications': 'Értesítések',
|
||||
'notifications.versionAvailable.title': 'Elérhető frissítés',
|
||||
|
||||
@@ -189,15 +189,28 @@ const id: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'settings.notificationPreferences.noChannels': 'Belum ada saluran notifikasi yang dikonfigurasi. Minta admin untuk mengatur notifikasi email atau webhook.',
|
||||
'settings.webhookUrl.label': 'Webhook URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Masukkan URL webhook Discord, Slack, atau kustom untuk menerima notifikasi.',
|
||||
'settings.webhookUrl.save': 'Simpan',
|
||||
'settings.webhookUrl.saved': 'Webhook URL tersimpan',
|
||||
'settings.webhookUrl.test': 'Uji',
|
||||
'settings.webhookUrl.testSuccess': 'Test webhook berhasil dikirim',
|
||||
'settings.webhookUrl.testFailed': 'Test webhook gagal',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'admin.notifications.title': 'Notifikasi',
|
||||
'admin.notifications.hint': 'Pilih satu saluran notifikasi. Hanya satu yang bisa aktif sekaligus.',
|
||||
'admin.notifications.none': 'Dinonaktifkan',
|
||||
@@ -218,6 +231,22 @@ const id: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Test webhook berhasil dikirim',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Test webhook gagal',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Admin webhook selalu berjalan jika URL dikonfigurasi',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Atur saluran mana yang mengirimkan notifikasi khusus admin (mis. peringatan versi).',
|
||||
'admin.smtp.title': 'Email & Notifikasi',
|
||||
'admin.smtp.hint': 'Konfigurasi SMTP untuk pengiriman notifikasi email.',
|
||||
|
||||
@@ -1763,14 +1763,27 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'URL webhook',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Inserisci il tuo URL webhook Discord, Slack o personalizzato per ricevere notifiche.',
|
||||
'settings.webhookUrl.save': 'Salva',
|
||||
'settings.webhookUrl.saved': 'URL webhook salvato',
|
||||
'settings.webhookUrl.test': 'Test',
|
||||
'settings.webhookUrl.testSuccess': 'Webhook di test inviato con successo',
|
||||
'settings.webhookUrl.testFailed': 'Invio webhook di test fallito',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1781,6 +1794,22 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Webhook di test inviato con successo',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Invio webhook di test fallito',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Il webhook admin si attiva automaticamente quando è configurato un URL',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Configura quali canali consegnano le notifiche admin (es. avvisi di versione). Il webhook si attiva automaticamente se è impostato un URL webhook admin.',
|
||||
'admin.tabs.notifications': 'Notifiche',
|
||||
'notifications.versionAvailable.title': 'Aggiornamento disponibile',
|
||||
|
||||
@@ -1762,14 +1762,27 @@ const nl: Record<string, string> = {
|
||||
'settings.webhookUrl.label': 'Webhook-URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Voer je Discord-, Slack- of aangepaste webhook-URL in om meldingen te ontvangen.',
|
||||
'settings.webhookUrl.save': 'Opslaan',
|
||||
'settings.webhookUrl.saved': 'Webhook-URL opgeslagen',
|
||||
'settings.webhookUrl.test': 'Testen',
|
||||
'settings.webhookUrl.testSuccess': 'Test-webhook succesvol verzonden',
|
||||
'settings.webhookUrl.testFailed': 'Test-webhook mislukt',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1780,6 +1793,22 @@ const nl: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Test-webhook succesvol verzonden',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Test-webhook mislukt',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Admin-webhook verstuurt automatisch als er een URL is ingesteld',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Stel in via welke kanalen admin-meldingen worden bezorgd (bijv. versie-updates). De webhook verstuurt automatisch als er een admin-webhook-URL is ingesteld.',
|
||||
'admin.tabs.notifications': 'Meldingen',
|
||||
'notifications.versionAvailable.title': 'Update beschikbaar',
|
||||
|
||||
@@ -1596,6 +1596,22 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Testowy webhook wysłany pomyślnie',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Wysyłanie testowego webhooka nie powiodło się',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Webhook admina wysyła automatycznie, gdy URL jest skonfigurowany',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Skonfiguruj, które kanały dostarczają powiadomienia admina (np. alerty o wersjach). Webhook wysyła automatycznie, gdy ustawiony jest URL webhooka admina.',
|
||||
'admin.webhook.hint': 'Pozwól użytkownikom konfigurować własne adresy URL webhooka dla powiadomień (Discord, Slack itp.).',
|
||||
'settings.notificationsDisabled': 'Powiadomienia nie są skonfigurowane.',
|
||||
@@ -1603,14 +1619,27 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'settings.webhookUrl.label': 'URL webhooka',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Wprowadź adres URL webhooka Discord, Slack lub własnego, aby otrzymywać powiadomienia.',
|
||||
'settings.webhookUrl.save': 'Zapisz',
|
||||
'settings.webhookUrl.saved': 'URL webhooka zapisany',
|
||||
'settings.webhookUrl.test': 'Testuj',
|
||||
'settings.webhookUrl.testSuccess': 'Testowy webhook wysłany pomyślnie',
|
||||
'settings.webhookUrl.testFailed': 'Wysyłanie testowego webhooka nie powiodło się',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'settings.notificationsActive': 'Aktywny kanał',
|
||||
'settings.notificationsManagedByAdmin': 'Zdarzenia konfigurowane przez administratora.',
|
||||
'settings.mustChangePassword': 'Musisz zmienić hasło przed kontynuowaniem.',
|
||||
|
||||
@@ -1759,14 +1759,27 @@ const ru: Record<string, string> = {
|
||||
'settings.webhookUrl.label': 'URL вебхука',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': 'Введите URL вашего вебхука Discord, Slack или пользовательского для получения уведомлений.',
|
||||
'settings.webhookUrl.save': 'Сохранить',
|
||||
'settings.webhookUrl.saved': 'URL вебхука сохранён',
|
||||
'settings.webhookUrl.test': 'Тест',
|
||||
'settings.webhookUrl.testSuccess': 'Тестовый вебхук успешно отправлен',
|
||||
'settings.webhookUrl.testFailed': 'Ошибка тестового вебхука',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1777,6 +1790,22 @@ const ru: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': 'Тестовый вебхук успешно отправлен',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': 'Ошибка тестового вебхука',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': 'Вебхук администратора отправляется автоматически при наличии URL',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': 'Настройте, какие каналы доставляют уведомления администратора (например, оповещения о версиях). Вебхук отправляется автоматически, если задан URL вебхука администратора.',
|
||||
'admin.tabs.notifications': 'Уведомления',
|
||||
'notifications.versionAvailable.title': 'Доступно обновление',
|
||||
|
||||
@@ -1759,14 +1759,27 @@ const zh: Record<string, string> = {
|
||||
'settings.webhookUrl.label': 'Webhook URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': '输入您的 Discord、Slack 或自定义 Webhook URL 以接收通知。',
|
||||
'settings.webhookUrl.save': '保存',
|
||||
'settings.webhookUrl.saved': 'Webhook URL 已保存',
|
||||
'settings.webhookUrl.test': '测试',
|
||||
'settings.webhookUrl.testSuccess': '测试 Webhook 发送成功',
|
||||
'settings.webhookUrl.testFailed': '测试 Webhook 失败',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationPreferences.inapp': 'In-App',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.email': 'Email',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'admin.notifications.emailPanel.title': 'Email (SMTP)',
|
||||
'admin.notifications.webhookPanel.title': 'Webhook',
|
||||
'admin.notifications.inappPanel.title': 'In-App',
|
||||
@@ -1777,6 +1790,22 @@ const zh: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': '测试 Webhook 发送成功',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': '测试 Webhook 失败',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': '配置 URL 后管理员 Webhook 自动触发',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': '配置哪些渠道发送管理员通知(如版本更新提醒)。设置管理员 Webhook URL 后,Webhook 将自动触发。',
|
||||
'admin.tabs.notifications': '通知',
|
||||
'notifications.versionAvailable.title': '有可用更新',
|
||||
|
||||
@@ -186,15 +186,28 @@ const zhTw: Record<string, string> = {
|
||||
'settings.notificationPreferences.email': '電子郵件',
|
||||
'settings.notificationPreferences.webhook': 'Webhook',
|
||||
'settings.notificationPreferences.inapp': '應用程式內',
|
||||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||||
'settings.notificationPreferences.noChannels': '未配置通知渠道。請聯絡管理員設定電子郵件或 Webhook 通知。',
|
||||
'settings.webhookUrl.label': 'Webhook URL',
|
||||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||||
'settings.webhookUrl.hint': '輸入您的 Discord、Slack 或自訂 Webhook URL 以接收通知。',
|
||||
'settings.webhookUrl.save': '儲存',
|
||||
'settings.webhookUrl.saved': 'Webhook URL 已儲存',
|
||||
'settings.webhookUrl.test': '測試',
|
||||
'settings.webhookUrl.testSuccess': '測試 Webhook 傳送成功',
|
||||
'settings.webhookUrl.testFailed': '測試 Webhook 傳送失敗',
|
||||
'settings.ntfyUrl.topicLabel': 'Ntfy Topic',
|
||||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||||
'settings.ntfyUrl.serverLabel': 'Ntfy Server URL (optional)',
|
||||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||||
'settings.ntfyUrl.hint': 'Enter your ntfy topic to receive push notifications. Leave server blank to use the default configured by your admin.',
|
||||
'settings.ntfyUrl.tokenLabel': 'Access Token (optional)',
|
||||
'settings.ntfyUrl.tokenHint': 'Required for password-protected topics.',
|
||||
'settings.ntfyUrl.saved': 'Ntfy settings saved',
|
||||
'settings.ntfyUrl.test': 'Test',
|
||||
'settings.ntfyUrl.testSuccess': 'Test ntfy notification sent successfully',
|
||||
'settings.ntfyUrl.testFailed': 'Test ntfy notification failed',
|
||||
'settings.ntfyUrl.clearToken': 'Clear',
|
||||
'settings.ntfyUrl.tokenCleared': 'Access token cleared',
|
||||
'settings.notificationsDisabled': '通知尚未配置。請聯絡管理員啟用電子郵件或 Webhook 通知。',
|
||||
'settings.notificationsActive': '活躍頻道',
|
||||
'settings.notificationsManagedByAdmin': '通知事件由管理員配置。',
|
||||
@@ -218,6 +231,22 @@ const zhTw: Record<string, string> = {
|
||||
'admin.notifications.adminWebhookPanel.testSuccess': '測試 Webhook 傳送成功',
|
||||
'admin.notifications.adminWebhookPanel.testFailed': '測試 Webhook 傳送失敗',
|
||||
'admin.notifications.adminWebhookPanel.alwaysOnHint': '配置 URL 後,管理員 Webhook 始終觸發',
|
||||
'admin.notifications.ntfy': 'Ntfy',
|
||||
'admin.notifications.testNtfy': 'Send test ntfy',
|
||||
'admin.notifications.testNtfySuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.testNtfyFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
|
||||
'admin.notifications.adminNtfyPanel.hint': 'This ntfy topic is used exclusively for admin notifications (e.g. version alerts). It is separate from per-user topics and always fires when configured.',
|
||||
'admin.notifications.adminNtfyPanel.serverLabel': 'Ntfy Server URL',
|
||||
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
|
||||
'admin.notifications.adminNtfyPanel.topicLabel': 'Admin Topic',
|
||||
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
|
||||
'admin.notifications.adminNtfyPanel.tokenLabel': 'Access Token (optional)',
|
||||
'admin.notifications.adminNtfyPanel.saved': 'Admin ntfy settings saved',
|
||||
'admin.notifications.adminNtfyPanel.test': 'Send test ntfy',
|
||||
'admin.notifications.adminNtfyPanel.testSuccess': 'Test ntfy sent successfully',
|
||||
'admin.notifications.adminNtfyPanel.testFailed': 'Test ntfy failed',
|
||||
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin ntfy always fires when a topic is configured',
|
||||
'admin.notifications.adminNotificationsHint': '配置哪些渠道傳遞僅管理員通知(例如版本提醒)。',
|
||||
'admin.smtp.title': '郵件與通知',
|
||||
'admin.smtp.hint': '用於傳送電子郵件通知的 SMTP 配置。',
|
||||
|
||||
@@ -66,6 +66,7 @@ const ADMIN_CHANNEL_LABEL_KEYS: Record<string, string> = {
|
||||
inapp: 'settings.notificationPreferences.inapp',
|
||||
email: 'settings.notificationPreferences.email',
|
||||
webhook: 'settings.notificationPreferences.webhook',
|
||||
ntfy: 'settings.notificationPreferences.ntfy',
|
||||
}
|
||||
|
||||
function AdminNotificationsPanel({ t, toast }: { t: (k: string) => string; toast: ReturnType<typeof useToast> }) {
|
||||
@@ -78,7 +79,7 @@ function AdminNotificationsPanel({ t, toast }: { t: (k: string) => string; toast
|
||||
|
||||
if (!matrix) return <p style={{ fontSize: 12, color: 'var(--text-faint)', fontStyle: 'italic', padding: 16 }}>Loading…</p>
|
||||
|
||||
const visibleChannels = (['inapp', 'email', 'webhook'] as const).filter(ch => {
|
||||
const visibleChannels = (['inapp', 'email', 'webhook', 'ntfy'] as const).filter(ch => {
|
||||
if (!matrix.available_channels[ch]) return false
|
||||
return matrix.event_types.some((evt: string) => matrix.implemented_combos[evt]?.includes(ch))
|
||||
})
|
||||
@@ -1168,15 +1169,16 @@ export default function AdminPage(): React.ReactElement {
|
||||
const activeChans = rawChannels === 'none' ? [] : rawChannels.split(',').map((c: string) => c.trim())
|
||||
const emailActive = activeChans.includes('email')
|
||||
const webhookActive = activeChans.includes('webhook')
|
||||
const ntfyActive = activeChans.includes('ntfy')
|
||||
|
||||
const setChannels = async (email: boolean, webhook: boolean) => {
|
||||
const chans = [email && 'email', webhook && 'webhook'].filter(Boolean).join(',') || 'none'
|
||||
const setChannels = async (email: boolean, webhook: boolean, ntfy: boolean) => {
|
||||
const chans = [email && 'email', webhook && 'webhook', ntfy && 'ntfy'].filter(Boolean).join(',') || 'none'
|
||||
setSmtpValues(prev => ({ ...prev, notification_channels: chans }))
|
||||
try {
|
||||
await authApi.updateAppSettings({ notification_channels: chans })
|
||||
} catch {
|
||||
// Revert state on failure
|
||||
const reverted = [emailActive && 'email', webhookActive && 'webhook'].filter(Boolean).join(',') || 'none'
|
||||
const reverted = [emailActive && 'email', webhookActive && 'webhook', ntfyActive && 'ntfy'].filter(Boolean).join(',') || 'none'
|
||||
setSmtpValues(prev => ({ ...prev, notification_channels: reverted }))
|
||||
toast.error(t('common.error'))
|
||||
}
|
||||
@@ -1207,7 +1209,7 @@ export default function AdminPage(): React.ReactElement {
|
||||
<p className="text-xs text-slate-400 mt-1">{t('admin.smtp.hint')}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setChannels(!emailActive, webhookActive)}
|
||||
onClick={() => setChannels(!emailActive, webhookActive, ntfyActive)}
|
||||
className="relative inline-flex h-6 w-11 items-center rounded-full transition-colors flex-shrink-0"
|
||||
style={{ background: emailActive ? 'var(--text-primary)' : 'var(--border-primary)' }}
|
||||
>
|
||||
@@ -1283,7 +1285,7 @@ export default function AdminPage(): React.ReactElement {
|
||||
<p className="text-xs text-slate-400 mt-1">{t('admin.webhook.hint')}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setChannels(emailActive, !webhookActive)}
|
||||
onClick={() => setChannels(emailActive, !webhookActive, ntfyActive)}
|
||||
className="relative inline-flex h-6 w-11 items-center rounded-full transition-colors flex-shrink-0"
|
||||
style={{ background: webhookActive ? 'var(--text-primary)' : 'var(--border-primary)' }}
|
||||
>
|
||||
@@ -1293,6 +1295,24 @@ export default function AdminPage(): React.ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Ntfy Panel */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="px-6 py-4 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="font-semibold text-slate-900">{t('admin.notifications.ntfy')}</h2>
|
||||
<p className="text-xs text-slate-400 mt-1">{t('admin.ntfy.hint') || 'Allow users to configure their own ntfy topics for push notifications.'}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setChannels(emailActive, webhookActive, !ntfyActive)}
|
||||
className="relative inline-flex h-6 w-11 items-center rounded-full transition-colors flex-shrink-0"
|
||||
style={{ background: ntfyActive ? 'var(--text-primary)' : 'var(--border-primary)' }}
|
||||
>
|
||||
<span className="absolute left-0.5 h-5 w-5 rounded-full bg-white transition-transform duration-200"
|
||||
style={{ transform: ntfyActive ? 'translateX(20px)' : 'translateX(0)' }} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* In-App Panel */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-slate-100 flex items-center justify-between">
|
||||
@@ -1358,6 +1378,89 @@ export default function AdminPage(): React.ReactElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Admin Ntfy Panel */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-slate-100">
|
||||
<h2 className="font-semibold text-slate-900">{t('admin.notifications.adminNtfyPanel.title')}</h2>
|
||||
<p className="text-xs text-slate-400 mt-1">{t('admin.notifications.adminNtfyPanel.hint')}</p>
|
||||
</div>
|
||||
<div className="p-6 space-y-3">
|
||||
{smtpLoaded && (
|
||||
<>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-500 mb-1">{t('admin.notifications.adminNtfyPanel.serverLabel')}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={smtpValues.admin_ntfy_server || ''}
|
||||
onChange={e => setSmtpValues(prev => ({ ...prev, admin_ntfy_server: e.target.value }))}
|
||||
placeholder={t('admin.notifications.adminNtfyPanel.serverPlaceholder')}
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-500 mb-1">{t('admin.notifications.adminNtfyPanel.topicLabel')}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={smtpValues.admin_ntfy_topic || ''}
|
||||
onChange={e => setSmtpValues(prev => ({ ...prev, admin_ntfy_topic: e.target.value }))}
|
||||
placeholder={t('admin.notifications.adminNtfyPanel.topicPlaceholder')}
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-500 mb-1">{t('admin.notifications.adminNtfyPanel.tokenLabel')}</label>
|
||||
<input
|
||||
type="password"
|
||||
value={smtpValues.admin_ntfy_token === '••••••••' ? '' : smtpValues.admin_ntfy_token || ''}
|
||||
onChange={e => setSmtpValues(prev => ({ ...prev, admin_ntfy_token: e.target.value }))}
|
||||
placeholder={smtpValues.admin_ntfy_token === '••••••••' ? '••••••••' : ''}
|
||||
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="px-6 pb-4 flex items-center gap-2 border-t border-slate-100 pt-4">
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
await authApi.updateAppSettings({
|
||||
admin_ntfy_server: smtpValues.admin_ntfy_server || '',
|
||||
admin_ntfy_topic: smtpValues.admin_ntfy_topic || '',
|
||||
...(smtpValues.admin_ntfy_token && smtpValues.admin_ntfy_token !== '••••••••'
|
||||
? { admin_ntfy_token: smtpValues.admin_ntfy_token }
|
||||
: {}),
|
||||
})
|
||||
toast.success(t('admin.notifications.adminNtfyPanel.saved'))
|
||||
} catch { toast.error(t('common.error')) }
|
||||
}}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-lg text-sm font-medium hover:bg-slate-800 transition-colors">
|
||||
<Save className="w-4 h-4" />{t('common.save')}
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
const topic = smtpValues.admin_ntfy_topic?.trim()
|
||||
if (!topic) return
|
||||
try {
|
||||
const token = smtpValues.admin_ntfy_token && smtpValues.admin_ntfy_token !== '••••••••'
|
||||
? smtpValues.admin_ntfy_token : null
|
||||
const result = await notificationsApi.testNtfy({
|
||||
topic,
|
||||
server: smtpValues.admin_ntfy_server || null,
|
||||
token,
|
||||
})
|
||||
if (result.success) toast.success(t('admin.notifications.adminNtfyPanel.testSuccess'))
|
||||
else toast.error(result.error || t('admin.notifications.adminNtfyPanel.testFailed'))
|
||||
} catch { toast.error(t('admin.notifications.adminNtfyPanel.testFailed')) }
|
||||
}}
|
||||
disabled={!smtpValues.admin_ntfy_topic?.trim()}
|
||||
className="px-4 py-2 border border-slate-300 text-slate-700 rounded-lg text-sm font-medium hover:bg-slate-50 transition-colors disabled:opacity-40"
|
||||
>
|
||||
{t('admin.notifications.adminNtfyPanel.test')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<AdminNotificationsPanel t={t} toast={toast} />
|
||||
|
||||
@@ -61,6 +61,10 @@ export const notificationHandlers = [
|
||||
return HttpResponse.json({ success: true });
|
||||
}),
|
||||
|
||||
http.post('/api/notifications/test-ntfy', async () => {
|
||||
return HttpResponse.json({ success: true });
|
||||
}),
|
||||
|
||||
http.post('/api/notifications/in-app/:id/respond', async ({ request, params }) => {
|
||||
const body = await request.json() as { response: string };
|
||||
return HttpResponse.json({
|
||||
|
||||
Reference in New Issue
Block a user