Move the ntfy alert sink to Settings, shared by all alert rules
Alert rules no longer carry their own ntfy topic/server; Settings now holds one process-wide ntfy sink (with its own "send test notification"), and the Alerts panel is left to just define rule conditions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ae4e550c1f
commit
18c2d72d22
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { Stats } from '../lib/api'
|
||||
import { cssContentUrl, type ColorScheme, type CssEntry } from '../lib/api'
|
||||
import { cssContentUrl, sendTestAlertNotification, type ColorScheme, type CssEntry } from '../lib/api'
|
||||
import { useSettingsPanel } from '../lib/useSettingsPanel'
|
||||
import { useDocsNav, type DocsTarget } from '../lib/docsNav'
|
||||
import { DocsPanel } from './Docs'
|
||||
@@ -147,11 +147,47 @@ function SettingsPanel({ panel }: { panel: ReturnType<typeof useSettingsPanel> }
|
||||
const [themeFilename, setThemeFilename] = useState('')
|
||||
const [themeContent, setThemeContent] = useState('')
|
||||
const [themeLinkUrl, setThemeLinkUrl] = useState('')
|
||||
const [ntfyTopicInput, setNtfyTopicInput] = useState('')
|
||||
const [ntfyServerInput, setNtfyServerInput] = useState('')
|
||||
const [ntfyTestError, setNtfyTestError] = useState<string | null>(null)
|
||||
const [ntfyTestSuccess, setNtfyTestSuccess] = useState(false)
|
||||
const [ntfyTesting, setNtfyTesting] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setMaxLogsInput(panel.settings?.max_logs != null ? String(panel.settings.max_logs) : '')
|
||||
}, [panel.settings?.max_logs])
|
||||
|
||||
useEffect(() => {
|
||||
setNtfyTopicInput(panel.settings?.ntfy_topic ?? '')
|
||||
setNtfyServerInput(panel.settings?.ntfy_server ?? '')
|
||||
}, [panel.settings?.ntfy_topic, panel.settings?.ntfy_server])
|
||||
|
||||
function handleNtfyTopicBlur() {
|
||||
panel.setNtfySink(ntfyTopicInput.trim() || null, panel.settings?.ntfy_server ?? null)
|
||||
}
|
||||
|
||||
function handleNtfyServerBlur() {
|
||||
panel.setNtfySink(panel.settings?.ntfy_topic ?? null, ntfyServerInput.trim() || null)
|
||||
}
|
||||
|
||||
async function handleNtfyTest() {
|
||||
setNtfyTestError(null)
|
||||
setNtfyTestSuccess(false)
|
||||
if (!ntfyTopicInput.trim()) {
|
||||
setNtfyTestError('Enter a topic to send a test notification.')
|
||||
return
|
||||
}
|
||||
setNtfyTesting(true)
|
||||
try {
|
||||
await sendTestAlertNotification(ntfyTopicInput.trim(), ntfyServerInput.trim() || null)
|
||||
setNtfyTestSuccess(true)
|
||||
} catch (err) {
|
||||
setNtfyTestError(err instanceof Error ? err.message : 'Failed to send test notification')
|
||||
} finally {
|
||||
setNtfyTesting(false)
|
||||
}
|
||||
}
|
||||
|
||||
function handleMaxLogsBlur() {
|
||||
const trimmed = maxLogsInput.trim()
|
||||
if (trimmed === '') {
|
||||
@@ -369,6 +405,42 @@ function SettingsPanel({ panel }: { panel: ReturnType<typeof useSettingsPanel> }
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="mb-2 flex items-center gap-1.5">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wide text-text-subtle">Ntfy sink</h3>
|
||||
<HelpIcon sectionId="alerts" label="Help: Ntfy sink" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="topic"
|
||||
value={ntfyTopicInput}
|
||||
onChange={(e) => setNtfyTopicInput(e.target.value)}
|
||||
onBlur={handleNtfyTopicBlur}
|
||||
className="rounded border border-border-soft bg-surface-1 px-2 py-1 text-xs text-text placeholder:text-text-subtle focus:border-border-strong focus:outline-none"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="https://ntfy.sh"
|
||||
value={ntfyServerInput}
|
||||
onChange={(e) => setNtfyServerInput(e.target.value)}
|
||||
onBlur={handleNtfyServerBlur}
|
||||
className="rounded border border-border-soft bg-surface-1 px-2 py-1 text-xs text-text placeholder:text-text-subtle focus:border-border-strong focus:outline-none"
|
||||
/>
|
||||
{ntfyTestError && <div className="text-xs text-danger-text-strong">{ntfyTestError}</div>}
|
||||
{ntfyTestSuccess && <div className="text-xs text-text-secondary">Test notification sent.</div>}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleNtfyTest}
|
||||
disabled={ntfyTesting}
|
||||
className="self-start rounded border border-border-soft px-2 py-1 text-xs text-text hover:bg-surface-2 disabled:opacity-50"
|
||||
>
|
||||
{ntfyTesting ? 'Sending…' : 'Send test notification'}
|
||||
</button>
|
||||
<p className="text-[11px] text-text-faint">Every alert rule delivers here — see the Alerts panel to define rules.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 className="mb-2 text-xs font-semibold uppercase tracking-wide text-text-subtle">Import CSS</h3>
|
||||
<form onSubmit={handleImport} className="flex flex-col gap-2">
|
||||
|
||||
Reference in New Issue
Block a user