diff --git a/datapoint.go b/datapoint.go index f851a5b..07346e8 100644 --- a/datapoint.go +++ b/datapoint.go @@ -21,16 +21,14 @@ const ( ) type Datapoint struct { - ID int - Group string - Name string - Datatype DatapointType - LastValue time.Time `db:"last_value"` - DatapointValueJSON []byte `db:"datapoint_value_json"` - LastDatapointValue DatapointValue - Found bool - NodataProblemSeconds int `db:"nodata_problem_seconds"` - NodataIsProblem bool `db:"nodata_is_problem"` + ID int + Group string + Name string + Datatype DatapointType + LastValue time.Time `db:"last_value"` + DatapointValueJSON []byte `db:"datapoint_value_json"` + LastDatapointValue DatapointValue + Found bool } type DatapointValue struct { @@ -58,13 +56,13 @@ func (dp DatapointValue) Value() any { // {{{ return nil } // }}} -func (dp DatapointValue) FormattedTime() string { // {{{ +func (dp DatapointValue) FormattedTime() string {// {{{ if dp.ValueDateTime.Valid { return dp.ValueDateTime.Time.Format("2006-01-02 15:04:05") } return "invalid time" -} // }}} -func (dp Datapoint) Update() (err error) { // {{{ +}// }}} +func (dp Datapoint) Update() (err error) {// {{{ name := strings.TrimSpace(dp.Name) if name == "" { err = errors.New("Name can't be empty") @@ -73,47 +71,23 @@ func (dp Datapoint) Update() (err error) { // {{{ if dp.ID == 0 { _, err = service.Db.Conn.Exec( - `INSERT INTO datapoint("group", name, datatype) VALUES($1, $2, $3, $4)`, + `INSERT INTO datapoint("group", name, datatype) VALUES($1, $2, $3)`, dp.Group, name, dp.Datatype, - dp.NodataProblemSeconds, ) } else { - /* Keep nodata_is_problem as is unless the nodata_problem_seconds is changed. - * Otherwise unnecessary nodata problems could be notified when updating unrelated - * datapoint properties. */ _, err = service.Db.Conn.Exec( - ` - UPDATE datapoint - SET - "group"=$2, - name=$3, - datatype=$4, - nodata_problem_seconds=$5, - nodata_is_problem = ( - CASE - WHEN $5 != nodata_problem_seconds THEN false - ELSE - nodata_is_problem - END - ) - WHERE - id=$1 - `, + `UPDATE datapoint SET "group"=$2, name=$3, datatype=$4 WHERE id=$1`, dp.ID, dp.Group, name, dp.Datatype, - dp.NodataProblemSeconds, ) } - if err != nil { - err = werr.Wrap(err) - } return -} // }}} +}// }}} func DatapointAdd[T any](name string, value T) (err error) { // {{{ row := service.Db.Conn.QueryRow(`SELECT id, datatype FROM datapoint WHERE name=$1`, name) @@ -146,7 +120,7 @@ func DatapointAdd[T any](name string, value T) (err error) { // {{{ return } - service.Db.Conn.Exec(`UPDATE datapoint SET last_value = NOW(), nodata_is_problem = false WHERE id=$1`, dpID) + service.Db.Conn.Exec(`UPDATE datapoint SET last_value = NOW() WHERE name=$1`, name) return } // }}} @@ -279,14 +253,14 @@ func DatapointRetrieve(id int, name string) (dp Datapoint, err error) { // {{{ return } // }}} -func DatapointDelete(id int) (err error) { // {{{ +func DatapointDelete(id int) (err error) {// {{{ _, err = service.Db.Conn.Exec(`DELETE FROM datapoint WHERE id=$1`, id) if err != nil { err = werr.Wrap(err).WithData(id) } return -} // }}} -func DatapointValues(id int) (values []DatapointValue, err error) { // {{{ +}// }}} +func DatapointValues(id int) (values []DatapointValue, err error) {// {{{ rows, err := service.Db.Conn.Queryx(`SELECT * FROM datapoint_value WHERE datapoint_id=$1 ORDER BY ts DESC LIMIT 500`, id) if err != nil { err = werr.Wrap(err).WithData(id) @@ -304,4 +278,4 @@ func DatapointValues(id int) (values []DatapointValue, err error) { // {{{ values = append(values, dpv) } return -} // }}} +}// }}} diff --git a/go.mod b/go.mod index 32bf233..d8dc4da 100644 --- a/go.mod +++ b/go.mod @@ -6,14 +6,14 @@ require ( git.gibonuddevalla.se/go/webservice v0.2.15 git.gibonuddevalla.se/go/wrappederror v0.3.4 github.com/expr-lang/expr v1.16.5 - github.com/jmoiron/sqlx v1.3.5 - github.com/lib/pq v1.10.9 ) require ( git.gibonuddevalla.se/go/dbschema v1.3.0 // indirect github.com/google/uuid v1.5.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect + github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/lib/pq v1.10.9 // indirect golang.org/x/net v0.17.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 03a3465..26c1b8f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ git.gibonuddevalla.se/go/dbschema v1.3.0 h1:HzFMR29tWfy/ibIjltTbIMI4inVktj/rh8bESALibgM= git.gibonuddevalla.se/go/dbschema v1.3.0/go.mod h1:BNw3q/574nXbGoeWyK+tLhRfggVkw2j2aXZzrBKC3ig= -git.gibonuddevalla.se/go/webservice v0.2.15 h1:ECe63fRDSrg3RJcgYV2pG+WsAQLVG8wvfHennz7aHsY= -git.gibonuddevalla.se/go/webservice v0.2.15/go.mod h1:3uBS6nLbK9qbuGzDls8MZD5Xr9ORY1Srbj6v06BIhws= +git.gibonuddevalla.se/go/webservice v0.2.12 h1:IcaIycmF7eO88RmFQkslHaKRWYxXdciVQXUAvJ36b4g= +git.gibonuddevalla.se/go/webservice v0.2.12/go.mod h1:3uBS6nLbK9qbuGzDls8MZD5Xr9ORY1Srbj6v06BIhws= git.gibonuddevalla.se/go/wrappederror v0.3.4 h1:dcKp9/+QrZSO3S4fVnq7yG2p7DUZVmlztBAb/OzoZNY= git.gibonuddevalla.se/go/wrappederror v0.3.4/go.mod h1:j4w320Hk1wvhOPjUaK4GgLvmtnjUUM5yVu6JFO1OCSc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/main.go b/main.go index c0f557b..883457f 100644 --- a/main.go +++ b/main.go @@ -140,8 +140,6 @@ func main() { // {{{ service.Register("/configuration", false, false, pageConfiguration) service.Register("/entry/{datapoint}", false, false, entryDatapoint) - go nodataLoop() - err = service.Start() if err != nil { logger.Error("webserver", "error", werr.Wrap(err)) @@ -555,15 +553,11 @@ func pageDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { return } - var nodataSeconds int - nodataSeconds, _ = strconv.Atoi(r.FormValue("nodata_seconds")) - var dp Datapoint dp.ID = id dp.Group = r.FormValue("group") dp.Name = r.FormValue("name") dp.Datatype = DatapointType(r.FormValue("datatype")) - dp.NodataProblemSeconds = nodataSeconds err = dp.Update() if err != nil { httpError(w, werr.Wrap(err).Log()) diff --git a/nodata.go b/nodata.go deleted file mode 100644 index b30a239..0000000 --- a/nodata.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - // External - werr "git.gibonuddevalla.se/go/wrappederror" - - // Standard - "database/sql" - "time" -) - -// nodataLoop checks if datapoint last_value is larger than the nodata_problem_seconds period and -// marks them as problems. They are then notified. -func nodataLoop() { - var ids []int - var err error - - // TODO - should be configurable - ticker := time.NewTicker(time.Second * 5) - for { - <-ticker.C - ids, err = nodataDatapointIDs() - if err != nil { - err = werr.Wrap(err).Log() - logger.Error("nodata", "error", err) - continue - } - - if len(ids) == 0 { - continue - } - - logger.Info("nodata", "problem_ids", ids) - } -} - -func nodataDatapointIDs() (ids []int, err error) { - ids = []int{} - - var rows *sql.Rows - rows, err = service.Db.Conn.Query(` - UPDATE datapoint - SET - nodata_is_problem = true - FROM ( - SELECT - id - FROM - datapoint - WHERE - NOT nodata_is_problem AND - extract(EPOCH from (NOW() - last_value))::int > nodata_problem_seconds - ) AS subquery - WHERE - datapoint.id = subquery.id - RETURNING - datapoint.id - - `) - if err != nil { - err = werr.Wrap(err) - return - } - defer rows.Close() - - var id int - for rows.Next() { - if err = rows.Scan(&id); err != nil { - err = werr.Wrap(err) - return - } - ids = append(ids, id) - } - return -} diff --git a/sql/00014.sql b/sql/00014.sql deleted file mode 100644 index e31a5d5..0000000 --- a/sql/00014.sql +++ /dev/null @@ -1,4 +0,0 @@ -ALTER TABLE datapoint ADD COLUMN nodata_problem_seconds INT4 NOT NULL DEFAULT 0; -ALTER TABLE datapoint ADD COLUMN nodata_is_problem BOOL NOT NULL DEFAULT false; - -CREATE INDEX datapoint_last_value_idx ON public.datapoint ("last_value"); diff --git a/static/css/datapoints.css b/static/css/datapoints.css index 8333e8e..1963b13 100644 --- a/static/css/datapoints.css +++ b/static/css/datapoints.css @@ -19,7 +19,7 @@ body { } body { background: #282828; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: #d5c4a1; font-size: 11pt; @@ -48,16 +48,25 @@ a:hover { b { font-weight: 500; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: #202020; color: #d5c4a1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; } button { background: #202020; @@ -88,16 +97,6 @@ span.seconds { label { user-select: none; } -.description { - border: 1px solid #737373; - color: #3f9da1; - background: #202020; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} #datapoints { display: grid; grid-template-columns: repeat(5, min-content); @@ -138,7 +137,6 @@ label { } .widgets .label { margin-top: 4px; - white-space: nowrap; } .widgets input[type="text"], .widgets textarea { diff --git a/static/css/main.css b/static/css/main.css index c2dc070..e24674f 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -19,7 +19,7 @@ body { } body { background: #282828; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: #d5c4a1; font-size: 11pt; @@ -48,16 +48,25 @@ a:hover { b { font-weight: 500; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: #202020; color: #d5c4a1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; } button { background: #202020; @@ -88,16 +97,6 @@ span.seconds { label { user-select: none; } -.description { - border: 1px solid #737373; - color: #3f9da1; - background: #202020; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} #layout { display: grid; grid-template-areas: "menu content"; diff --git a/static/css/problems.css b/static/css/problems.css index 080965f..5b6316c 100644 --- a/static/css/problems.css +++ b/static/css/problems.css @@ -19,7 +19,7 @@ body { } body { background: #282828; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: #d5c4a1; font-size: 11pt; @@ -48,16 +48,25 @@ a:hover { b { font-weight: 500; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: #202020; color: #d5c4a1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; } button { background: #202020; @@ -88,16 +97,6 @@ span.seconds { label { user-select: none; } -.description { - border: 1px solid #737373; - color: #3f9da1; - background: #202020; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} #problems-list, #acknowledged-list { display: grid; diff --git a/static/css/theme.css b/static/css/theme.css index 104cf3d..68c59d9 100644 --- a/static/css/theme.css +++ b/static/css/theme.css @@ -19,7 +19,7 @@ body { } body { background: #282828; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: #d5c4a1; font-size: 11pt; @@ -48,16 +48,25 @@ a:hover { b { font-weight: 500; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: #202020; color: #d5c4a1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; } button { background: #202020; @@ -88,13 +97,3 @@ span.seconds { label { user-select: none; } -.description { - border: 1px solid #737373; - color: #3f9da1; - background: #202020; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} diff --git a/static/css/trigger_edit.css b/static/css/trigger_edit.css index b2600b6..477f462 100644 --- a/static/css/trigger_edit.css +++ b/static/css/trigger_edit.css @@ -19,7 +19,7 @@ body { } body { background: #282828; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: #d5c4a1; font-size: 11pt; @@ -48,16 +48,25 @@ a:hover { b { font-weight: 500; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: #202020; color: #d5c4a1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; } button { background: #202020; @@ -88,16 +97,6 @@ span.seconds { label { user-select: none; } -.description { - border: 1px solid #737373; - color: #3f9da1; - background: #202020; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} .widgets { display: grid; grid-template-columns: min-content 1fr; diff --git a/static/js/datapoint_edit.mjs b/static/js/datapoint_edit.mjs index dfe5e9c..611011c 100644 --- a/static/js/datapoint_edit.mjs +++ b/static/js/datapoint_edit.mjs @@ -1,7 +1,7 @@ export class UI { constructor() { document.addEventListener('keydown', evt=>this.keyHandler(evt)) - document.querySelector('input[name="group"]').focus() + document.querySelector('input[name="name"]').focus() } keyHandler(evt) { if (!(evt.altKey && evt.shiftKey)) diff --git a/static/less/datapoints.less b/static/less/datapoints.less index 770db5f..26ee63d 100644 --- a/static/less/datapoints.less +++ b/static/less/datapoints.less @@ -47,7 +47,6 @@ .label { margin-top: 4px; - white-space: nowrap; } input[type="text"], textarea { diff --git a/static/less/theme.less b/static/less/theme.less index 11ae2fc..513db5f 100644 --- a/static/less/theme.less +++ b/static/less/theme.less @@ -44,7 +44,7 @@ body { body { background: @bg1; - font-family: sans-serif; + font-family: "Roboto", sans-serif; font-weight: 300; color: @text1; font-size: 11pt; @@ -80,16 +80,27 @@ b { font-weight: @bold; } +.roboto-light { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-style: normal; +} + +.roboto-medium { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-style: normal; +} + input[type="text"], textarea, select { - font-family: monospace; + font-family: "Roboto Mono", monospace; background: @bg2; color: @text1; padding: 4px 8px; border: none; font-size: 1em; - line-height: 1.5em; // fix for chrome hiding underscores } button { @@ -127,14 +138,3 @@ span.seconds { label { user-select: none; } - -.description { - border: 1px solid .lighterOrDarker(@bg3, 25%)[@result]; - color: @color4; - background: @bg2; - padding: 4px 8px; - margin-top: 8px; - white-space: nowrap; - width: min-content; - border-radius: 8px; -} diff --git a/views/pages/datapoint_edit.gotmpl b/views/pages/datapoint_edit.gotmpl index 9d65b50..9e9ee66 100644 --- a/views/pages/datapoint_edit.gotmpl +++ b/views/pages/datapoint_edit.gotmpl @@ -25,13 +25,6 @@ -
No data
problem time
(seconds)
-
- -
A problem is raised and notified if an entry isn't made within this time.
-
Set to 0 to disable.
-
-
{{ if eq .Data.Datapoint.ID 0 }} diff --git a/views/pages/datapoint_values.gotmpl b/views/pages/datapoint_values.gotmpl index fe4651c..f568b95 100644 --- a/views/pages/datapoint_values.gotmpl +++ b/views/pages/datapoint_values.gotmpl @@ -2,8 +2,19 @@ {{ $version := .VERSION }} + + {{ block "page_label" . }}{{end}} +
+ +
+
{{ range .Data.Values }}
{{ format_time .Ts }}