462196e29b
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
89 lines
3.1 KiB
Go
89 lines
3.1 KiB
Go
package settings
|
|
|
|
// R-388 slice 1 (`08-alarm-ladder.md` §8.1, `09` §3 decision 200; operator answers 2026-10-12):
|
|
// the notification page shows THREE group switches instead of one switch per detector. A group is a
|
|
// view over the SAME `enabled_events` list — saving a group writes all its detectors into it, so
|
|
// nothing on the wire and nothing on the hub changes.
|
|
//
|
|
// Every detector the page can save belongs to EXACTLY ONE group. Pinned by
|
|
// TestR388_EveryPageSwitchIsInExactlyOneGroup (web), which reads the rendered page's switches and
|
|
// fails when a new detector gets a checkbox but no group.
|
|
|
|
// Notification group keys (also the form-field stems `group_<key>` / `group_<key>_shown`).
|
|
const (
|
|
NotifGroupMachine = "machine" // „A gépem és a meghajtóim" — the household acts
|
|
NotifGroupApps = "apps" // „Az alkalmazásaim"
|
|
NotifGroupHandled = "handled" // „Amit mi intézünk" — we act; the operator always gets these
|
|
)
|
|
|
|
// Group states as the page renders them.
|
|
const (
|
|
NotifGroupOn = "on"
|
|
NotifGroupOff = "off"
|
|
NotifGroupCustom = "custom" // some of its detectors on, some off — „egyedi"
|
|
)
|
|
|
|
// NotificationGroup is one switch on the notification page and the detectors behind it.
|
|
type NotificationGroup struct {
|
|
Key string
|
|
Events []string
|
|
}
|
|
|
|
// NotificationGroups is the §8.1 membership table, in page order.
|
|
var NotificationGroups = []NotificationGroup{
|
|
{Key: NotifGroupMachine, Events: []string{
|
|
"storage_disconnected", "storage_reconnected", "disk_warning", "disk_critical", "offbox_enlarge_blocked",
|
|
}},
|
|
{Key: NotifGroupApps, Events: []string{
|
|
"app_stopped_unhealthy", "app_start_failed", "app_update_held", "app_update_undone",
|
|
}},
|
|
{Key: NotifGroupHandled, Events: []string{
|
|
"backup_failed", "db_dump_failed", "backup_integrity_failed", "crossdrive_failed",
|
|
"expected_backup_missed", "expected_dbdump_missed", "node_down", "health_critical", "health_recovered",
|
|
}},
|
|
}
|
|
|
|
// NotificationGroupByKey returns the group with this key, or false.
|
|
func NotificationGroupByKey(key string) (NotificationGroup, bool) {
|
|
for _, g := range NotificationGroups {
|
|
if g.Key == key {
|
|
return g, true
|
|
}
|
|
}
|
|
return NotificationGroup{}, false
|
|
}
|
|
|
|
// NotificationGroupState reports whether all, none or some of the group's detectors are in enabled.
|
|
// An unknown key reads as off (renders unchecked, and the save leaves the details authoritative).
|
|
func NotificationGroupState(enabled []string, key string) string {
|
|
g, ok := NotificationGroupByKey(key)
|
|
if !ok {
|
|
return NotifGroupOff
|
|
}
|
|
set := make(map[string]bool, len(enabled))
|
|
for _, e := range enabled {
|
|
set[e] = true
|
|
}
|
|
on := 0
|
|
for _, e := range g.Events {
|
|
if set[e] {
|
|
on++
|
|
}
|
|
}
|
|
switch {
|
|
case on == len(g.Events):
|
|
return NotifGroupOn
|
|
case on == 0:
|
|
return NotifGroupOff
|
|
default:
|
|
return NotifGroupCustom
|
|
}
|
|
}
|
|
|
|
// GroupState is the template's view of NotificationGroupState over this household's list.
|
|
// VALUE receiver on purpose: a pointer receiver compiles and passes vet, then 500s at render
|
|
// (`.claude/rules/ui-hungarian.md`).
|
|
func (p NotificationPrefs) GroupState(key string) string {
|
|
return NotificationGroupState(p.EnabledEvents, key)
|
|
}
|