Compare commits

..

4 Commits

Author SHA1 Message Date
Magnus Åhall
adab2ab67d In-page addition of datapoints to triggers 2024-05-30 14:33:43 +02:00
Magnus Åhall
68abb894a6 Don't erase datapoints when used in triggers. 2024-05-30 13:32:04 +02:00
Magnus Åhall
9eecf946f8 Configurable interval for nodata checks 2024-05-30 13:31:51 +02:00
Magnus Åhall
c45724f5d8 Fixed bug in creating new datatype 2024-05-30 13:05:42 +02:00
5 changed files with 89 additions and 9 deletions

View File

@ -1,5 +1,6 @@
package main package main
type SmonConfiguration struct { type SmonConfiguration struct {
LogFile string LogFile string
NodataInterval int `json:"nodata_interval"` // in seconds
} }

View File

@ -73,7 +73,7 @@ func (dp Datapoint) Update() (err error) { // {{{
if dp.ID == 0 { if dp.ID == 0 {
_, err = service.Db.Conn.Exec( _, err = service.Db.Conn.Exec(
`INSERT INTO datapoint("group", name, datatype) VALUES($1, $2, $3, $4)`, `INSERT INTO datapoint("group", name, datatype, nodata_problem_seconds) VALUES($1, $2, $3, $4)`,
dp.Group, dp.Group,
name, name,
dp.Datatype, dp.Datatype,
@ -283,6 +283,37 @@ func DatapointRetrieve(id int, name string) (dp Datapoint, err error) { // {{{
return return
} // }}} } // }}}
func DatapointDelete(id int) (err error) { // {{{ func DatapointDelete(id int) (err error) { // {{{
var dpName string
row := service.Db.Conn.QueryRow(`SELECT name FROM public.datapoint WHERE id = $1`, id)
err = row.Scan(&dpName)
if err != nil {
err = werr.Wrap(err).WithData(id)
return
}
var rows *sql.Rows
rows, err = service.Db.Conn.Query(`SELECT name FROM public.trigger WHERE datapoints ? $1`, dpName)
if err != nil {
err = werr.Wrap(err).WithData(dpName)
return
}
defer rows.Close()
var triggerNames []string
var name string
for rows.Next() {
err = rows.Scan(&name)
if err != nil {
err = werr.Wrap(err)
return
}
triggerNames = append(triggerNames, name)
}
if len(triggerNames) > 0 {
return werr.New("Datapoint '%s' used in the following triggers: %s", dpName, strings.Join(triggerNames, ", "))
}
_, err = service.Db.Conn.Exec(`DELETE FROM datapoint WHERE id=$1`, id) _, err = service.Db.Conn.Exec(`DELETE FROM datapoint WHERE id=$1`, id)
if err != nil { if err != nil {
err = werr.Wrap(err).WithData(id) err = werr.Wrap(err).WithData(id)

40
main.go
View File

@ -21,6 +21,7 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"slices"
"sort" "sort"
"strconv" "strconv"
"time" "time"
@ -38,6 +39,7 @@ var (
parsedTemplates map[string]*template.Template parsedTemplates map[string]*template.Template
componentFilenames []string componentFilenames []string
notificationManager notification.Manager notificationManager notification.Manager
smonConf SmonConfiguration
//go:embed sql //go:embed sql
sqlFS embed.FS sqlFS embed.FS
@ -88,7 +90,6 @@ func main() { // {{{
os.Exit(1) os.Exit(1)
} }
smonConf := SmonConfiguration{}
j, _ := json.Marshal(service.Config.Application) j, _ := json.Marshal(service.Config.Application)
json.Unmarshal(j, &smonConf) json.Unmarshal(j, &smonConf)
logFile, err = os.OpenFile(smonConf.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) logFile, err = os.OpenFile(smonConf.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
@ -96,6 +97,10 @@ func main() { // {{{
logger.Error("application", "error", err) logger.Error("application", "error", err)
return return
} }
if smonConf.NodataInterval < 10 {
logger.Error("application → nodata_interval has to be larger or equal to 10.")
return
}
service.SetDatabase(sqlProvider) service.SetDatabase(sqlProvider)
service.SetStaticFS(staticFS, "static") service.SetStaticFS(staticFS, "static")
@ -134,6 +139,7 @@ func main() { // {{{
service.Register("/triggers", false, false, pageTriggers) service.Register("/triggers", false, false, pageTriggers)
service.Register("/trigger/edit/{id}", false, false, pageTriggerEdit) service.Register("/trigger/edit/{id}", false, false, pageTriggerEdit)
service.Register("/trigger/edit/{id}/{sectionID}", false, false, pageTriggerEdit) service.Register("/trigger/edit/{id}/{sectionID}", false, false, pageTriggerEdit)
service.Register("/trigger/addDatapoint/{id}/{datapointName}", false, false, pageTriggerDatapointAdd)
service.Register("/trigger/update/{id}", false, false, pageTriggerUpdate) service.Register("/trigger/update/{id}", false, false, pageTriggerUpdate)
service.Register("/trigger/run/{id}", false, false, pageTriggerRun) service.Register("/trigger/run/{id}", false, false, pageTriggerRun)
@ -721,6 +727,38 @@ func pageTriggerEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { //
page.Render(w) page.Render(w)
} // }}} } // }}}
func pageTriggerDatapointAdd(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
triggerID := r.PathValue("id")
dpName := r.PathValue("datapointName")
id, err := strconv.Atoi(triggerID)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
var trigger Trigger
if id > 0 {
trigger, err = TriggerRetrieve(id)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
}
if !slices.Contains(trigger.Datapoints, dpName) {
trigger.Datapoints = append(trigger.Datapoints, dpName)
}
err = trigger.Update()
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
j, _ := json.Marshal(struct{ OK bool }{OK: true})
w.Header().Add("Content-Type", "application/json")
w.Write(j)
} // }}}
func pageTriggerUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{ func pageTriggerUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
idStr := r.PathValue("id") idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr) id, err := strconv.Atoi(idStr)

View File

@ -25,7 +25,7 @@ func nodataLoop() {
var err error var err error
// TODO - should be configurable // TODO - should be configurable
ticker := time.NewTicker(time.Second * 5) ticker := time.NewTicker(time.Second * time.Duration(smonConf.NodataInterval))
for { for {
<-ticker.C <-ticker.C
datapoints, err = nodataDatapoints() datapoints, err = nodataDatapoints()

View File

@ -66,7 +66,7 @@ export class UI {
}) })
.catch(err => alert(err)) .catch(err => alert(err))
}//}}} }//}}}
chooseDatapoint() {//{{{ async chooseDatapoint() {//{{{
const dlg = document.getElementById('dlg-datapoints') const dlg = document.getElementById('dlg-datapoints')
const datapoint = document.getElementById('datapoint').value const datapoint = document.getElementById('datapoint').value
const dp = this.datapoints.find(dp => dp.Name == datapoint) const dp = this.datapoints.find(dp => dp.Name == datapoint)
@ -77,8 +77,10 @@ export class UI {
} }
this.trigger.addDatapoint(dp) this.trigger.addDatapoint(dp)
dlg.close() .then(() => {
this.render() dlg.close()
this.render()
})
}//}}} }//}}}
deleteDatapoint(name) {//{{{ deleteDatapoint(name) {//{{{
if (!confirm(`Delete ${name}?`)) { if (!confirm(`Delete ${name}?`)) {
@ -147,7 +149,15 @@ export class Trigger {
}) })
.catch(err => alert(err)) .catch(err => alert(err))
}//}}} }//}}}
addDatapoint(dp) {//{{{ async addDatapoint(dp) {//{{{
this.datapoints[dp.Name] = dp return fetch(`/trigger/addDatapoint/${this.id}/${dp.Name}`)
.then(data => data.json())
.then(json => {
if (!json.OK) {
alert(json.Error)
return
}
this.datapoints[dp.Name] = dp
})
}//}}} }//}}}
} }