Implement NotifyOnStatusChange feature for nodes and enhance Telegram notifications
CI / Backend (build + test) (push) Successful in 1m24s
CI / Frontend (lint + typecheck + build) (push) Successful in 34s

- Added `NotifyOnStatusChange` property to the `Node` class and related DTOs to allow individual node configuration for status change notifications.
- Updated `NodeHealthCheckService` to send Telegram notifications to admins when a node's status changes, based on the new property.
- Enhanced the `ITelegramNotifier` interface with a method for notifying admins about node status changes.
- Modified the frontend to include a checkbox for `NotifyOnStatusChange` in the node editing dialog, allowing admins to easily configure this setting.
- Updated API documentation to reflect the new `notifyOnStatusChange` parameter in the node update endpoint.
- Added tests to ensure the correct behavior of the new feature and its integration with existing functionality.
This commit is contained in:
Leonid Pershin
2026-07-23 11:04:38 +03:00
parent 2f6bb26e97
commit fb97093bd6
20 changed files with 1272 additions and 6 deletions
@@ -17,12 +17,22 @@ export function EditNodeDialog({ node, open, onOpenChange }: { node: NodeDto; op
const [baseAddress, setBaseAddress] = useState(node.baseAddress)
const [location, setLocation] = useState(node.location ?? '')
const [isEnabled, setIsEnabled] = useState(node.isEnabled)
const [notifyOnStatusChange, setNotifyOnStatusChange] = useState(node.notifyOnStatusChange)
const [username, setUsername] = useState(node.username)
const [password, setPassword] = useState('')
const mutation = useMutation({
mutationFn: () =>
updateNode(node.id, name.trim(), baseAddress.trim(), location.trim() || undefined, isEnabled, username.trim() || undefined, password || undefined),
updateNode(
node.id,
name.trim(),
baseAddress.trim(),
location.trim() || undefined,
isEnabled,
notifyOnStatusChange,
username.trim() || undefined,
password || undefined,
),
onSuccess: async () => {
toast.success(t('admin.nodes.updated'))
await queryClient.invalidateQueries({ queryKey: ['admin-nodes'] })
@@ -66,6 +76,14 @@ export function EditNodeDialog({ node, open, onOpenChange }: { node: NodeDto; op
<input type="checkbox" checked={isEnabled} onChange={(e) => setIsEnabled(e.target.checked)} />
{t('admin.nodes.enabled')}
</label>
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={notifyOnStatusChange}
onChange={(e) => setNotifyOnStatusChange(e.target.checked)}
/>
{t('admin.nodes.notifyOnStatusChange')}
</label>
<div className="flex flex-col gap-1.5">
<Label htmlFor="editUsername">
{t('admin.nodes.username')} ({t('admin.nodes.optional')})