okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

dawntui: webhooks on listView: filter, pane, confirm only for destructive actions, add on ctrl+o82b9457

main
4.5 KiB107 linesraw
1// Gallery states of the Webhooks screen; TestShotGallery/webhooks draws them.
2// Without ALBEDO_SHOT_DIR they are only built, which keeps each one buildable.
3package tui
4
5import (
6	"errors"
7
8	tea "charm.land/bubbletea/v2"
9)
10
11// galleryHooks are the fixtures every webhooks state starts from: one queued
12// hook, one quiet hook under the same session, and one off hook under another.
13var galleryHooks = []webhookEntry{
14	{ID: "wh1", Session: "s", Name: "deploy", Enabled: true, URL: "https://albedo.example/extensions/webhooks/hooks/wh1/deliveries", Header: "x-hub-signature-256", Prefix: "sha256=", Queued: 2, Deferred: "session busy"},
15	{ID: "wh3", Session: "s", Name: "alerts", Enabled: true, URL: "/extensions/webhooks/hooks/wh3/deliveries", Header: "x-albedo-signature", Prefix: "sha256="},
16	{ID: "wh2", Session: "t", Name: "grafana", URL: "/extensions/webhooks/hooks/wh2/deliveries", Header: "x-albedo-signature", Prefix: "sha256="},
17}
18
19func init() {
20	enter := tea.KeyPressMsg{Code: tea.KeyEnter}
21	down := tea.KeyPressMsg{Code: tea.KeyDown}
22	shiftTab := tea.KeyPressMsg{Code: tea.KeyTab, Mod: tea.ModShift}
23	ctrl := func(r rune) tea.Msg { return tea.KeyPressMsg{Code: r, Mod: tea.ModCtrl} }
24	typed := func(text string) []tea.Msg {
25		var keys []tea.Msg
26		for _, r := range text {
27			keys = append(keys, tea.KeyPressMsg{Code: r, Text: string(r)})
28		}
29		return keys
30	}
31	registerShots("webhooks",
32		shotState{"list", webhooksShot(nil)},
33		shotState{"list-agent-on", webhooksShot(func(m *WebhooksPageModel) { m.AgentManagement = true })},
34		shotState{"cursor-off", webhooksShot(nil, down, down)},
35		shotState{"filtering", webhooksShot(nil, typed("grafana")...)},
36		shotState{"filter-session", webhooksShot(nil, typed("release")...)},
37		shotState{"no-match", webhooksShot(nil, typed("zzz")...)},
38		shotState{"confirm-delete", webhooksShot(nil, ctrl('d'))},
39		shotState{"confirm-new-secret", webhooksShot(nil, ctrl('g'))},
40		shotState{"saving", webhooksShot(nil, enter)},
41		shotState{"save-failed", func(w, h int) string {
42			m := webhooksModel(w, h, nil)
43			m, _ = m.Update(enter)
44			m, _ = m.Update(webhooksSavedMsg{Gen: m.Generation, Err: errors.New("daemon refused the change: webhook etag is stale")})
45			return m.View()
46		}},
47		shotState{"notice", webhooksShot(func(m *WebhooksPageModel) {
48			m.Notice = "deploy disabled. New deliveries will receive a 404 response."
49		})},
50		shotState{"copied-url", webhooksShot(nil, ctrl('l'))},
51		shotState{"not-listening", webhooksShot(func(m *WebhooksPageModel) { m.Mounted = false })},
52		shotState{"loading", func(w, h int) string {
53			m := NewWebhooksPageModel(nil, "s")
54			m.SetSize(w, h)
55			return m.View()
56		}},
57		shotState{"empty", func(w, h int) string {
58			m := NewWebhooksPageModel(nil, "s")
59			m.SetSize(w, h)
60			m, _ = m.Update(webhooksLoadedMsg{Gen: m.Generation, Mounted: true, Sessions: webhookSessions})
61			return m.View()
62		}},
63		shotState{"load-failed", func(w, h int) string {
64			m := NewWebhooksPageModel(nil, "s")
65			m.SetSize(w, h)
66			m, _ = m.Update(webhooksLoadedMsg{Gen: m.Generation, Err: errors.New("daemon connection unavailable")})
67			return m.View()
68		}},
69		shotState{"form-add", webhooksShot(nil, ctrl('o'))},
70		shotState{"form-add-session", webhooksShot(nil, ctrl('o'), shiftTab)},
71		shotState{"form-typed", webhooksShot(nil, append([]tea.Msg{ctrl('o')}, typed("ci-deploys")...)...)},
72		shotState{"form-invalid", webhooksShot(nil, ctrl('o'), ctrl('s'))},
73		shotState{"form-edit", webhooksShot(nil, ctrl('e'))},
74		shotState{"reveal", func(w, h int) string {
75			m := webhooksModel(w, h, nil)
76			m.Reveal = &webhookSecret{Hook: "deploy", Session: "s", Secret: "whsec_9fQ2xLr7Tq1mZ0vBcW4yHs8dNe3KpA6u"}
77			return m.View()
78		}},
79		shotState{"reveal-copied", func(w, h int) string {
80			m := webhooksModel(w, h, nil)
81			m.Reveal = &webhookSecret{Hook: "deploy", Session: "s", Secret: "whsec_9fQ2xLr7Tq1mZ0vBcW4yHs8dNe3KpA6u"}
82			m, _ = m.Update(ctrl('l'))
83			return m.View()
84		}},
85	)
86}
87
88// webhooksModel is the screen loaded with the gallery's hooks.
89func webhooksModel(width, height int, setup func(*WebhooksPageModel)) WebhooksPageModel {
90	m := NewWebhooksPageModel(nil, "s")
91	m.SetSize(width, height)
92	m, _ = m.Update(webhooksLoadedMsg{Gen: m.Generation, Mounted: true, Sessions: webhookSessions, Hooks: galleryHooks})
93	if setup != nil {
94		setup(&m)
95	}
96	return m
97}
98
99func webhooksShot(setup func(*WebhooksPageModel), keys ...tea.Msg) func(width, height int) string {
100	return func(width, height int) string {
101		m := webhooksModel(width, height, setup)
102		for _, key := range keys {
103			m, _ = m.Update(key)
104		}
105		return m.View()
106	}
107}