From aa368c0b0dbbe7154b16f7b3a383793942ef1949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Sun, 30 Jun 2024 22:10:01 +0200 Subject: [PATCH 1/4] Store datapoint values with the problems --- problem.go | 27 +++++++++++++-------------- sql/00022.sql | 4 ++++ trigger.go | 17 +++++++++-------- 3 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 sql/00022.sql diff --git a/problem.go b/problem.go index 68a8695..b8615d2 100644 --- a/problem.go +++ b/problem.go @@ -10,18 +10,19 @@ import ( "time" ) -type Problem struct { +type Problem struct {// {{{ ID int Start time.Time End sql.NullTime Acknowledged bool + Datapoints map[string]any TriggerID int `json:"trigger_id"` TriggerName string `json:"trigger_name"` AreaName string `json:"area_name"` SectionName string `json:"section_name"` -} +}// }}} -func ProblemsRetrieve() (problems []Problem, err error) { +func ProblemsRetrieve() (problems []Problem, err error) {// {{{ problems = []Problem{} row := service.Db.Conn.QueryRow(` SELECT @@ -83,9 +84,8 @@ func ProblemsRetrieve() (problems []Problem, err error) { err = we.Wrap(err) } return -} - -func ProblemStart(trigger Trigger) (problemID int, err error) { +}// }}} +func ProblemStart(trigger Trigger) (problemID int, err error) {// {{{ row := service.Db.Conn.QueryRow(` SELECT COUNT(id) FROM problem @@ -105,16 +105,16 @@ func ProblemStart(trigger Trigger) (problemID int, err error) { // Open up a new problem if no open exists. if openProblems == 0 { - row = service.Db.Conn.QueryRow(`INSERT INTO problem(trigger_id) VALUES($1) RETURNING id`, trigger.ID) + datapointValuesJson, _ := json.Marshal(trigger.DatapointValues) + row = service.Db.Conn.QueryRow(`INSERT INTO problem(trigger_id, datapoints) VALUES($1, $2) RETURNING id`, trigger.ID, datapointValuesJson) err = row.Scan(&problemID) if err != nil { err = we.Wrap(err).WithData(trigger) } } return -} - -func ProblemClose(trigger Trigger) (problemID int, err error) { +}// }}} +func ProblemClose(trigger Trigger) (problemID int, err error) {// {{{ row := service.Db.Conn.QueryRow(`UPDATE problem SET "end"=NOW() WHERE trigger_id=$1 AND "end" IS NULL RETURNING id`, trigger.ID) err = row.Scan(&problemID) @@ -128,13 +128,12 @@ func ProblemClose(trigger Trigger) (problemID int, err error) { return } return -} - -func ProblemAcknowledge(id int, state bool) (err error) { +}// }}} +func ProblemAcknowledge(id int, state bool) (err error) {// {{{ _, err = service.Db.Conn.Exec(`UPDATE problem SET "acknowledged"=$2 WHERE id=$1`, id, state) if err != nil { err = we.Wrap(err).WithData(id) return } return -} +}// }}} diff --git a/sql/00022.sql b/sql/00022.sql new file mode 100644 index 0000000..34e7d00 --- /dev/null +++ b/sql/00022.sql @@ -0,0 +1,4 @@ +ALTER TABLE public.problem ALTER COLUMN trigger_id DROP NOT NULL; +ALTER TABLE public.problem ADD COLUMN datapoints JSONB NOT NULL DEFAULT '{}'; +ALTER TABLE public.problem DROP CONSTRAINT problem_trigger_fk; +ALTER TABLE public.problem ADD CONSTRAINT problem_trigger_fk FOREIGN KEY (trigger_id) REFERENCES public."trigger"(id) ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/trigger.go b/trigger.go index 2c16eba..85f792f 100644 --- a/trigger.go +++ b/trigger.go @@ -14,11 +14,12 @@ import ( ) type Trigger struct { - ID int - Name string - SectionID int `db:"section_id"` - Expression string - Datapoints []string + ID int + Name string + SectionID int `db:"section_id"` + Expression string + Datapoints []string + DatapointValues map[string]any } func TriggerCreate(sectionID int, name string) (t Trigger, err error) { // {{{ @@ -231,9 +232,9 @@ func (t *Trigger) Run() (output any, err error) { // {{{ datapoints[dpname] = dp } - env := make(map[string]any) + t.DatapointValues = make(map[string]any) for dpName, dp := range datapoints { - env[dpName] = dp.LastDatapointValue.Value() + t.DatapointValues[dpName] = dp.LastDatapointValue.Value() } program, err := expr.Compile(t.Expression) @@ -241,7 +242,7 @@ func (t *Trigger) Run() (output any, err error) { // {{{ return } - output, err = expr.Run(program, env) + output, err = expr.Run(program, t.DatapointValues) if err != nil { return } From df714c750b6417e99ed1ee021ed3c683c74bfddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Thu, 4 Jul 2024 08:54:03 +0200 Subject: [PATCH 2/4] Info icon for problem values --- problem.go | 58 ++++++++++++++++++--------- static/css/default_light/problems.css | 6 ++- static/css/gruvbox/problems.css | 6 ++- static/less/problems.less | 6 ++- views/pages/problems.gotmpl | 29 ++++++++++++-- 5 files changed, 80 insertions(+), 25 deletions(-) diff --git a/problem.go b/problem.go index b8615d2..a8f0372 100644 --- a/problem.go +++ b/problem.go @@ -7,22 +7,26 @@ import ( // Standard "database/sql" "encoding/json" + "fmt" + "sort" + "strings" "time" ) -type Problem struct {// {{{ - ID int - Start time.Time - End sql.NullTime - Acknowledged bool - Datapoints map[string]any - TriggerID int `json:"trigger_id"` - TriggerName string `json:"trigger_name"` - AreaName string `json:"area_name"` - SectionName string `json:"section_name"` -}// }}} +type Problem struct { // {{{ + ID int + Start time.Time + End sql.NullTime + Acknowledged bool + Datapoints map[string]any + DatapointValues map[string]any `json:"datapoints"` + TriggerID int `json:"trigger_id"` + TriggerName string `json:"trigger_name"` + AreaName string `json:"area_name"` + SectionName string `json:"section_name"` +} // }}} -func ProblemsRetrieve() (problems []Problem, err error) {// {{{ +func ProblemsRetrieve() (problems []Problem, err error) { // {{{ problems = []Problem{} row := service.Db.Conn.QueryRow(` SELECT @@ -33,6 +37,7 @@ func ProblemsRetrieve() (problems []Problem, err error) {// {{{ p.start, p.end, p.acknowledged, + p.datapoints, t.id AS trigger_id, t.name AS trigger_name, a.name AS area_name, @@ -53,6 +58,7 @@ func ProblemsRetrieve() (problems []Problem, err error) {// {{{ null, null, false, + '{}', -1 AS trigger_id, CONCAT( 'NODATA: ', @@ -84,8 +90,8 @@ func ProblemsRetrieve() (problems []Problem, err error) {// {{{ err = we.Wrap(err) } return -}// }}} -func ProblemStart(trigger Trigger) (problemID int, err error) {// {{{ +} // }}} +func ProblemStart(trigger Trigger) (problemID int, err error) { // {{{ row := service.Db.Conn.QueryRow(` SELECT COUNT(id) FROM problem @@ -113,8 +119,8 @@ func ProblemStart(trigger Trigger) (problemID int, err error) {// {{{ } } return -}// }}} -func ProblemClose(trigger Trigger) (problemID int, err error) {// {{{ +} // }}} +func ProblemClose(trigger Trigger) (problemID int, err error) { // {{{ row := service.Db.Conn.QueryRow(`UPDATE problem SET "end"=NOW() WHERE trigger_id=$1 AND "end" IS NULL RETURNING id`, trigger.ID) err = row.Scan(&problemID) @@ -128,12 +134,26 @@ func ProblemClose(trigger Trigger) (problemID int, err error) {// {{{ return } return -}// }}} -func ProblemAcknowledge(id int, state bool) (err error) {// {{{ +} // }}} +func ProblemAcknowledge(id int, state bool) (err error) { // {{{ _, err = service.Db.Conn.Exec(`UPDATE problem SET "acknowledged"=$2 WHERE id=$1`, id, state) if err != nil { err = we.Wrap(err).WithData(id) return } return -}// }}} +} // }}} + +func (p Problem) FormattedValues() string { + out := []string{} + for key, val := range p.DatapointValues { + timeVal, ok := val.(time.Time) + if ok { + logger.Info("FOO", "timeVal", timeVal) + } + out = append(out, fmt.Sprintf("%s: %v", key, val)) + } + sort.Strings(out) + + return strings.Join(out, "\n") +} diff --git a/static/css/default_light/problems.css b/static/css/default_light/problems.css index 3a415de..b8d440b 100644 --- a/static/css/default_light/problems.css +++ b/static/css/default_light/problems.css @@ -30,6 +30,10 @@ #acknowledged-list .acknowledge img { height: 16px; } +#problems-list .info, +#acknowledged-list .info { + margin-right: 8px; +} #acknowledged-list.hidden { display: none; } @@ -41,7 +45,7 @@ } #areas .area .section { display: grid; - grid-template-columns: repeat(2, min-content); + grid-template-columns: repeat(3, min-content); grid-gap: 8px 12px; } #areas .area .section .name { diff --git a/static/css/gruvbox/problems.css b/static/css/gruvbox/problems.css index 6c014f7..0e69462 100644 --- a/static/css/gruvbox/problems.css +++ b/static/css/gruvbox/problems.css @@ -30,6 +30,10 @@ #acknowledged-list .acknowledge img { height: 16px; } +#problems-list .info, +#acknowledged-list .info { + margin-right: 8px; +} #acknowledged-list.hidden { display: none; } @@ -41,7 +45,7 @@ } #areas .area .section { display: grid; - grid-template-columns: repeat(2, min-content); + grid-template-columns: repeat(3, min-content); grid-gap: 8px 12px; } #areas .area .section .name { diff --git a/static/less/problems.less b/static/less/problems.less index 601a9b4..79f711f 100644 --- a/static/less/problems.less +++ b/static/less/problems.less @@ -32,6 +32,10 @@ height: 16px; } } + + .info { + margin-right: 8px; + } } #acknowledged-list.hidden{ @@ -47,7 +51,7 @@ .area { .section { display: grid; - grid-template-columns: repeat(2, min-content); + grid-template-columns: repeat(3, min-content); grid-gap: 8px 12px; .name { diff --git a/views/pages/problems.gotmpl b/views/pages/problems.gotmpl index 4df5aee..6076e94 100644 --- a/views/pages/problems.gotmpl +++ b/views/pages/problems.gotmpl @@ -34,13 +34,26 @@
{{ .AreaName }}
{{ .SectionName }}
-
+
+ + +
{{ else }}
{{ .AreaName }}
{{ .SectionName }}
{{ format_time .Start }}
-
+
+ {{ if .FormattedValues }} + + {{ else }} + + {{ end }} + + + + +
{{ end }} {{ end }} @@ -63,7 +76,9 @@
{{ .AreaName }}
{{ .SectionName }}
{{ format_time .Start }}
-
+
+ +
{{ end }} @@ -79,6 +94,7 @@
{{ $sectionName }}
{{ range $problems }} +
{{ .TriggerName }}
{{ if eq (.Start | html) "0001-01-01 00:00:00 +0000 UTC" }} @@ -86,6 +102,13 @@ {{ else }}
{{ format_time .Start }}
{{ end }} + + {{ if .FormattedValues }} +
+ {{ else }} +
+ {{ end }} + {{ end }} {{ end }} From a985f531ea17f0bb7e4a1cadb92c2615538ef51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Thu, 4 Jul 2024 09:21:24 +0200 Subject: [PATCH 3/4] Better datetime display for problems --- problem.go | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/problem.go b/problem.go index a8f0372..944942c 100644 --- a/problem.go +++ b/problem.go @@ -147,11 +147,29 @@ func ProblemAcknowledge(id int, state bool) (err error) { // {{{ func (p Problem) FormattedValues() string { out := []string{} for key, val := range p.DatapointValues { - timeVal, ok := val.(time.Time) - if ok { - logger.Info("FOO", "timeVal", timeVal) + var keyval string + + switch val.(type) { + case int: + keyval = fmt.Sprintf("%s: %d", key, val) + + case string: + if str, ok := val.(string); ok { + timeVal, err := time.Parse(time.RFC3339, str) + if err == nil { + formattedTime := timeVal.Format("2006-01-02 15:04:05") + keyval = fmt.Sprintf("%s: %s", key, formattedTime) + } else { + keyval = fmt.Sprintf("%s: %s", key, val) + } + } + + default: + keyval = fmt.Sprintf("%s: %v", key, val) } - out = append(out, fmt.Sprintf("%s: %v", key, val)) + + out = append(out, keyval) + } sort.Strings(out) From 0f69874475990627ec97d307764c36a7d7ab3396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Thu, 4 Jul 2024 09:21:36 +0200 Subject: [PATCH 4/4] Bumped to v28 --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 982f066..583ff95 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,7 @@ import ( "time" ) -const VERSION = "v27" +const VERSION = "v28" var ( logger *slog.Logger