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 diff --git a/problem.go b/problem.go index 68a8695..944942c 100644 --- a/problem.go +++ b/problem.go @@ -7,21 +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 - 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 @@ -32,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, @@ -52,6 +58,7 @@ func ProblemsRetrieve() (problems []Problem, err error) { null, null, false, + '{}', -1 AS trigger_id, CONCAT( 'NODATA: ', @@ -83,9 +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 @@ -105,16 +111,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 +134,44 @@ 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 { + 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, keyval) + + } + sort.Strings(out) + + return strings.Join(out, "\n") } 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/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/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 } 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 }}
{{ .TriggerName }}
{{ .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 }}