Manage notification channels instead of an ntfy topic

Mirrors the server's channels API: add/remove channels per user from the Users
section. Requires the matching server release.

Claude-Session: https://claude.ai/code/session_016mBLURvJoMuUEr9cB2RpUN
This commit is contained in:
Niklas Ye
2026-10-12 21:00:40 +02:00
parent 77f2d6775b
commit ec5df0449b
10 changed files with 405 additions and 174 deletions
+18 -14
View File
@@ -1,6 +1,7 @@
package tui
import (
"strings"
"testing"
"time"
@@ -196,29 +197,32 @@ func TestAlertRows_ShowIncidentLink(t *testing.T) {
}
}
// A user with no ntfy topic gets no pages of their own — the row has to say so
// A user with no channel gets no pages of their own — the row has to say so
// rather than leaving a blank that reads as "not loaded yet".
func TestUserManageRows_ShowMissingTopic(t *testing.T) {
topic := "terdut-niklas"
empty := ""
func TestUserManageRows_ShowMissingChannels(t *testing.T) {
m := NewModel(nil, "http://test", time.Minute, theme.GruvboxDark)
m.width, m.height = 120, 40
m.users = []api.User{
{ID: 1, Username: "niklas", NtfyTopic: &topic},
{ID: 1, Username: "niklas", Channels: []api.NotificationChannel{
{ID: 1, Type: "ntfy", Address: "terdut-niklas", Enabled: true}}},
{ID: 2, Username: "alex"},
// The server stores a blank topic as NULL, but a stale client or an older
// server can still hand one back; it means the same thing.
{ID: 3, Username: "sam", NtfyTopic: &empty},
{ID: 3, Username: "sam", Channels: []api.NotificationChannel{
{ID: 2, Type: "ntfy", Enabled: false}}},
}
m.rebuildUserManageTable()
rows := m.userManageTable.Rows()
if rows[0][2] != "terdut-niklas" {
t.Errorf("expected the topic in the row, got %q", rows[0][2])
if rows[0][2] != "ntfy" {
t.Errorf("expected the channel kind in the row, got %q", rows[0][2])
}
if rows[1][2] != "—" || rows[2][2] != "—" {
t.Errorf("expected an em dash for nil and empty topics, got %q and %q",
rows[1][2], rows[2][2])
if strings.Contains(rows[0][2], "terdut-niklas") {
t.Errorf("the row must not carry an address, got %q", rows[0][2])
}
if rows[1][2] != "—" {
t.Errorf("expected an em dash for a user with no channel, got %q", rows[1][2])
}
if rows[2][2] != "ntfy (off)" {
t.Errorf("expected a switched-off channel to say so, got %q", rows[2][2])
}
}
@@ -228,7 +232,7 @@ func TestUserManageRows_ShowMissingTopic(t *testing.T) {
func TestColumnWidthsFitTheTerminal(t *testing.T) {
for _, width := range []int{100, 110, 140, 200} {
// Five cells each, or six once a Team column is added. userManageColumns
// is five cells as well: username, email, topic, flags, created.
// is five cells as well: username, email, channels, flags, created.
for name, tc := range map[string]struct {
cols []table.Column
cells int