From 17a22caa5d6d8164aba9bc53ed9189f349d8bfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Sat, 29 Jun 2024 19:30:26 +0200 Subject: [PATCH] Time filtering of notifications --- main.go | 42 +++++++++++- notification_log.go | 13 ++-- static/css/default_light/default_light.css | 7 +- static/css/default_light/notifications.css | 45 ++++++++++++ static/css/gruvbox/default_light.css | 7 +- static/css/gruvbox/notifications.css | 45 ++++++++++++ static/less/default_light.less | 6 +- static/less/notifications.less | 57 ++++++++++++++++ views/pages/notifications.gotmpl | 79 +++++++++++++++++++++- 9 files changed, 291 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index fb11c0b..01a6cf4 100644 --- a/main.go +++ b/main.go @@ -1198,7 +1198,45 @@ func actionConfigurationNotificationDelete(w http.ResponseWriter, r *http.Reques } // }}} func pageNotifications(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{ - nss, err := notificationsSent() + var err error + + // GET parameters. + var timeFrom, timeTo time.Time + lastWeek := time.Now().Add(time.Duration(-7 * 24 * time.Hour)) + + timeFrom, err = parseHTMLDateTime(r.URL.Query().Get("f"), lastWeek) + if err != nil { + httpError(w, werr.Wrap(err).Log()) + return + } + + timeTo, err = parseHTMLDateTime(r.URL.Query().Get("t"), time.Now()) + if err != nil { + httpError(w, werr.Wrap(err).Log()) + return + } + + var presetTime int + now := time.Now() + presetStr := r.URL.Query().Get("preset") + if presetStr != "" { + presetTime, err = strconv.Atoi(presetStr) + if err != nil { + pageError(w, "/notifications", werr.Wrap(err).WithData(presetStr).Log()) + return + } + timeFrom = now.Add(time.Hour * -1 * time.Duration(presetTime)) + timeTo = now + } + + // Apply an optionally set offset (in seconds). + var offsetTime int + offsetTimeStr := r.URL.Query().Get("offset-time") + offsetTime, err = strconv.Atoi(offsetTimeStr) + timeFrom = timeFrom.Add(time.Second * time.Duration(offsetTime)) + timeTo = timeTo.Add(time.Second * time.Duration(offsetTime)) + + nss, err := notificationsSent(timeFrom, timeTo) if err != nil { pageError(w, "/", werr.Wrap(err).Log()) } @@ -1209,6 +1247,8 @@ func pageNotifications(w http.ResponseWriter, r *http.Request, _ *session.T) { / CONFIG: smonConfig.Settings, Data: map[string]any{ "Notifications": nss, + "TimeFrom": timeFrom.Format("2006-01-02T15:04:05"), + "TimeTo": timeTo.Format("2006-01-02T15:04:05"), }, } diff --git a/notification_log.go b/notification_log.go index d080cc9..c6d0a71 100644 --- a/notification_log.go +++ b/notification_log.go @@ -40,7 +40,7 @@ func notificationLog(notificationService *notification.Service, problemID int, e } } -func notificationsSent() (nss []NotificationSend, err error) { +func notificationsSent(from, to time.Time) (nss []NotificationSend, err error) { var rows *sqlx.Rows rows, err = service.Db.Conn.Queryx( ` @@ -57,15 +57,20 @@ func notificationsSent() (nss []NotificationSend, err error) { ns.error::varchar, ns.acknowledged - FROM - public.notification_send ns + FROM public.notification_send ns INNER JOIN notification n ON ns.notification_id = n.id INNER JOIN problem p ON ns.problem_id = p.id INNER JOIN "trigger" t ON p.trigger_id = t.id + WHERE + ns.send >= $1 AND + ns.send <= $2 ORDER BY send DESC - `) + `, + from, + to, + ) if err != nil { err = werr.Wrap(err) return diff --git a/static/css/default_light/default_light.css b/static/css/default_light/default_light.css index 57e3f8c..638f1a5 100644 --- a/static/css/default_light/default_light.css +++ b/static/css/default_light/default_light.css @@ -40,11 +40,16 @@ button:focus { #areas .area .section .name { font-weight: normal; } +dialog { + border-radius: 8px; +} +dialog, #datapoints, #problems-list, #acknowledged-list, #values, -#services { +#services, +#notifications { background-color: #fff !important; border: 1px solid #ddd; box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25); diff --git a/static/css/default_light/notifications.css b/static/css/default_light/notifications.css index b051c08..a39d982 100644 --- a/static/css/default_light/notifications.css +++ b/static/css/default_light/notifications.css @@ -1,3 +1,42 @@ +#time-select { + display: grid; + grid-template-columns: min-content min-content; + grid-gap: 6px 16px; + padding: 16px; + border: 1px solid #7bb8eb; + width: min-content; + border-radius: 6px; +} +#time-select button { + width: 100px; + margin-top: 12px; + justify-self: end; +} +#time-select #time-offsets { + display: grid; + grid-template-columns: min-content repeat(3, min-content); + grid-gap: 16px; + margin-top: 16px; + align-items: center; + justify-items: center; +} +#time-select #time-offsets .header-1 { + font-weight: bold; + justify-self: start; +} +#time-select #time-offsets .header-2 { + font-weight: bold; + justify-self: start; + grid-column: 2 / -1; +} +#time-select #time-offsets .preset { + white-space: nowrap; + justify-self: start; + padding-right: 32px; +} +input[type="datetime-local"] { + padding: 6px; +} #notifications { display: grid; grid-template-columns: repeat(5, min-content); @@ -18,3 +57,9 @@ font-weight: 800; color: #7bb8eb; } +#notifications .ok { + color: #0a0; +} +#notifications .error { + color: #a00; +} diff --git a/static/css/gruvbox/default_light.css b/static/css/gruvbox/default_light.css index 3361608..95d95f2 100644 --- a/static/css/gruvbox/default_light.css +++ b/static/css/gruvbox/default_light.css @@ -40,11 +40,16 @@ button:focus { #areas .area .section .name { font-weight: normal; } +dialog { + border-radius: 8px; +} +dialog, #datapoints, #problems-list, #acknowledged-list, #values, -#services { +#services, +#notifications { background-color: #fff !important; border: 1px solid #ddd; box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25); diff --git a/static/css/gruvbox/notifications.css b/static/css/gruvbox/notifications.css index c6a1d82..aaeab41 100644 --- a/static/css/gruvbox/notifications.css +++ b/static/css/gruvbox/notifications.css @@ -1,3 +1,42 @@ +#time-select { + display: grid; + grid-template-columns: min-content min-content; + grid-gap: 6px 16px; + padding: 16px; + border: 1px solid #777; + width: min-content; + border-radius: 6px; +} +#time-select button { + width: 100px; + margin-top: 12px; + justify-self: end; +} +#time-select #time-offsets { + display: grid; + grid-template-columns: min-content repeat(3, min-content); + grid-gap: 16px; + margin-top: 16px; + align-items: center; + justify-items: center; +} +#time-select #time-offsets .header-1 { + font-weight: bold; + justify-self: start; +} +#time-select #time-offsets .header-2 { + font-weight: bold; + justify-self: start; + grid-column: 2 / -1; +} +#time-select #time-offsets .preset { + white-space: nowrap; + justify-self: start; + padding-right: 32px; +} +input[type="datetime-local"] { + padding: 6px; +} #notifications { display: grid; grid-template-columns: repeat(5, min-content); @@ -18,3 +57,9 @@ font-weight: 800; color: #777; } +#notifications .ok { + color: #0a0; +} +#notifications .error { + color: #a00; +} diff --git a/static/less/default_light.less b/static/less/default_light.less index 542a083..ba51838 100644 --- a/static/less/default_light.less +++ b/static/less/default_light.less @@ -58,7 +58,11 @@ button { } } -#datapoints, #problems-list, #acknowledged-list, #values, #services { +dialog { + border-radius: 8px; +} + +dialog, #datapoints, #problems-list, #acknowledged-list, #values, #services, #notifications { background-color: #fff !important; border: 1px solid #ddd; box-shadow: 5px 5px 8px 0px rgba(0,0,0,0.25); diff --git a/static/less/notifications.less b/static/less/notifications.less index 8753486..62037d6 100644 --- a/static/less/notifications.less +++ b/static/less/notifications.less @@ -1,5 +1,54 @@ @import "theme-@{THEME}.less"; +#time-select { + display: grid; + grid-template-columns: min-content min-content; + grid-gap: 6px 16px; + + padding: 16px; + border: 1px solid @text3; + width: min-content; + border-radius: 6px; + + button { + //grid-column: ~"1 / -1"; + width: 100px; + margin-top: 12px; + justify-self: end; + } + + #time-offsets { + display: grid; + grid-template-columns: min-content repeat(3, min-content); + grid-gap: 16px; + margin-top: 16px; + + align-items: center; + justify-items: center; + + .header-1 { + font-weight: bold; + justify-self: start; + } + + .header-2 { + font-weight: bold; + justify-self: start; + grid-column: ~"2 / -1"; + } + + .preset { + white-space: nowrap; + justify-self: start; + padding-right: 32px; + } + } +} + +input[type="datetime-local"] { + padding: 6px; +} + #notifications { display: grid; grid-template-columns: repeat(5, min-content); @@ -21,4 +70,12 @@ font-weight: @bold; color: @text3; } + + .ok { + color: #0a0; + } + + .error { + color: #a00; + } } diff --git a/views/pages/notifications.gotmpl b/views/pages/notifications.gotmpl index f93e39a..afe39b3 100644 --- a/views/pages/notifications.gotmpl +++ b/views/pages/notifications.gotmpl @@ -4,6 +4,67 @@ {{ $version := .VERSION }} {{ $theme := .CONFIG.THEME }} + + +
+ + + +
+
From
+
To
+ + + +
+
Presets
+
Offsets
+ + + +
+
Hour
+
+ + + +
+
Day
+
+ + + +
+
Week
+
+ + + +
+
Month
+
+
+ +
+
Sent
@@ -13,10 +74,24 @@
Error
{{ range .Data.Notifications }}
{{ format_time .Sent }}
-
{{ if .OK }}✔{{ else }}✗{{ end }}
+
{{ if .OK }}{{ else }}{{ end }}
{{ .TriggerName }}
{{ .Prio }}:{{ .Service }}
-
{{ if .Error.Valid }}{{ .ErrorIndented }}{{ end }}
+
+ {{ if .Error.Valid }} + + +
+
{{ .ErrorIndented }}
+
+ +
+
+
+ {{ else }} + + {{ end }} +
{{ end }}