Adding datapoints to triggers
This commit is contained in:
parent
b0a0f9290e
commit
c746343dc0
@ -36,6 +36,7 @@ type DatapointValue struct {
|
|||||||
ValueInt sql.NullInt64 `db:"value_int"`
|
ValueInt sql.NullInt64 `db:"value_int"`
|
||||||
ValueString sql.NullString `db:"value_string"`
|
ValueString sql.NullString `db:"value_string"`
|
||||||
ValueDateTime sql.NullTime `db:"value_datetime"`
|
ValueDateTime sql.NullTime `db:"value_datetime"`
|
||||||
|
TemplateValue any
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dp DatapointValue) Value() any { // {{{
|
func (dp DatapointValue) Value() any { // {{{
|
||||||
|
45
main.go
45
main.go
@ -103,13 +103,17 @@ func main() { // {{{
|
|||||||
|
|
||||||
service.Register("/", false, false, staticHandler)
|
service.Register("/", false, false, staticHandler)
|
||||||
service.Register("/problems", false, false, pageProblems)
|
service.Register("/problems", false, false, pageProblems)
|
||||||
|
|
||||||
service.Register("/datapoints", false, false, pageDatapoints)
|
service.Register("/datapoints", false, false, pageDatapoints)
|
||||||
service.Register("/datapoint/edit/{id}", false, false, pageDatapointEdit)
|
service.Register("/datapoint/edit/{id}", false, false, pageDatapointEdit)
|
||||||
service.Register("/datapoint/update/{id}", false, false, pageDatapointUpdate)
|
service.Register("/datapoint/update/{id}", false, false, pageDatapointUpdate)
|
||||||
|
|
||||||
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/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)
|
||||||
|
|
||||||
service.Register("/configuration", false, false, pageConfiguration)
|
service.Register("/configuration", false, false, pageConfiguration)
|
||||||
service.Register("/entry/{datapoint}", false, false, entryDatapoint)
|
service.Register("/entry/{datapoint}", false, false, entryDatapoint)
|
||||||
|
|
||||||
@ -187,7 +191,7 @@ func entryDatapoint(w http.ResponseWriter, r *http.Request, sess *session.T) { /
|
|||||||
|
|
||||||
switch v := out.(type) {
|
switch v := out.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
// Trigger returning true - a problem occured
|
// Trigger returning true - a problem occurred
|
||||||
if v {
|
if v {
|
||||||
err = ProblemStart(trigger)
|
err = ProblemStart(trigger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -272,6 +276,7 @@ func pageIndex(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
|||||||
}
|
}
|
||||||
page.Render(w)
|
page.Render(w)
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
||||||
page := Page{
|
page := Page{
|
||||||
LAYOUT: "main",
|
LAYOUT: "main",
|
||||||
@ -297,7 +302,8 @@ func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
|||||||
page.Render(w)
|
page.Render(w)
|
||||||
return
|
return
|
||||||
} // }}}
|
} // }}}
|
||||||
func pageDatapoints(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
|
||||||
|
func pageDatapoints(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
|
||||||
page := Page{
|
page := Page{
|
||||||
LAYOUT: "main",
|
LAYOUT: "main",
|
||||||
PAGE: "datapoints",
|
PAGE: "datapoints",
|
||||||
@ -308,7 +314,13 @@ func pageDatapoints(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {
|
|||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Info("FOO", "dps", datapoints)
|
|
||||||
|
// The datapoint selector in trigger edit wants the raw data in JSON.
|
||||||
|
if r.URL.Query().Get("format") == "json" {
|
||||||
|
j, _ := json.Marshal(datapoints)
|
||||||
|
w.Write(j)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
page.Data = map[string]any{
|
page.Data = map[string]any{
|
||||||
"Datapoints": datapoints,
|
"Datapoints": datapoints,
|
||||||
@ -371,6 +383,7 @@ func pageDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) {
|
|||||||
w.Header().Add("Location", "/datapoints")
|
w.Header().Add("Location", "/datapoints")
|
||||||
w.WriteHeader(302)
|
w.WriteHeader(302)
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
func pageTriggers(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
func pageTriggers(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
||||||
areas, err := TriggersRetrieve()
|
areas, err := TriggersRetrieve()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -400,12 +413,27 @@ func pageTriggerEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { //
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creating a new trigger uses the edit function.
|
||||||
|
// ID == 0 - create a new trigger.
|
||||||
|
// ID > 0 - edit existing trigger.
|
||||||
var trigger Trigger
|
var trigger Trigger
|
||||||
|
if id > 0 {
|
||||||
trigger, err = TriggerRetrieve(id)
|
trigger, err = TriggerRetrieve(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// A new trigger needs to know which section it belongs to.
|
||||||
|
sectionIDStr := r.PathValue("sectionID")
|
||||||
|
if sectionIDStr != "" {
|
||||||
|
trigger.SectionID, err = strconv.Atoi(sectionIDStr)
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, we.Wrap(err).Log())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
datapoints := make(map[string]Datapoint)
|
datapoints := make(map[string]Datapoint)
|
||||||
for _, dpname := range trigger.Datapoints {
|
for _, dpname := range trigger.Datapoints {
|
||||||
@ -414,6 +442,7 @@ func pageTriggerEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { //
|
|||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
dp.LastDatapointValue.TemplateValue = dp.LastDatapointValue.Value()
|
||||||
datapoints[dpname] = dp
|
datapoints[dpname] = dp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,14 +469,23 @@ func pageTriggerUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { /
|
|||||||
}
|
}
|
||||||
|
|
||||||
var trigger Trigger
|
var trigger Trigger
|
||||||
|
if id > 0 {
|
||||||
trigger, err = TriggerRetrieve(id)
|
trigger, err = TriggerRetrieve(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
trigger.SectionID, err = strconv.Atoi(r.FormValue("sectionID"))
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, we.Wrap(err).Log())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trigger.Name = r.FormValue("name")
|
trigger.Name = r.FormValue("name")
|
||||||
trigger.Expression = r.FormValue("expression")
|
trigger.Expression = r.FormValue("expression")
|
||||||
|
trigger.Datapoints = r.Form["datapoints[]"]
|
||||||
err = trigger.Update()
|
err = trigger.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
@ -492,6 +530,7 @@ func pageTriggerRun(w http.ResponseWriter, r *http.Request, _ *session.T) { // {
|
|||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
w.Write(j)
|
w.Write(j)
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
func pageConfiguration(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
func pageConfiguration(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
|
||||||
areas, err := AreaRetrieve()
|
areas, err := AreaRetrieve()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
1
page.go
1
page.go
@ -52,7 +52,6 @@ func (p *Page) Render(w http.ResponseWriter) {
|
|||||||
"Data": p.Data,
|
"Data": p.Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("foo", "tmpl", tmpl)
|
|
||||||
err = tmpl.Execute(w, data)
|
err = tmpl.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, we.Wrap(err).Log())
|
httpError(w, we.Wrap(err).Log())
|
||||||
|
1
sql/00008.sql
Normal file
1
sql/00008.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE public."trigger" ADD CONSTRAINT trigger_sectionname_unique UNIQUE (section_id,"name");
|
@ -37,7 +37,7 @@ h2 {
|
|||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #3f9da1;
|
color: #fabd2f;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
@ -70,7 +70,7 @@ button {
|
|||||||
background: #202020;
|
background: #202020;
|
||||||
color: #d5c4a1;
|
color: #d5c4a1;
|
||||||
padding: 8px 32px;
|
padding: 8px 32px;
|
||||||
border: 1px solid #3a3a3a;
|
border: 1px solid #535353;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ h2 {
|
|||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #3f9da1;
|
color: #fabd2f;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
@ -70,7 +70,7 @@ button {
|
|||||||
background: #202020;
|
background: #202020;
|
||||||
color: #d5c4a1;
|
color: #d5c4a1;
|
||||||
padding: 8px 32px;
|
padding: 8px 32px;
|
||||||
border: 1px solid #3a3a3a;
|
border: 1px solid #535353;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
}
|
}
|
||||||
@ -137,12 +137,17 @@ button:focus {
|
|||||||
#areas .area .section {
|
#areas .area .section {
|
||||||
margin: 8px 16px;
|
margin: 8px 16px;
|
||||||
}
|
}
|
||||||
#areas .area .section > .name {
|
#areas .area .section .create {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content min-content;
|
||||||
|
grid-gap: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#areas .area .section .create .new {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
#areas .area .section .triggers a {
|
#areas .area .section > .name {
|
||||||
color: inherit;
|
font-weight: 500;
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
#areas .area .section .triggers .trigger {
|
#areas .area .section .triggers .trigger {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -155,5 +160,11 @@ button:focus {
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
#areas .area .section .triggers .trigger .label {
|
#areas .area .section .triggers .trigger .label {
|
||||||
color: #3f9da1;
|
color: inherit;
|
||||||
|
}
|
||||||
|
dialog {
|
||||||
|
background: #202020;
|
||||||
|
border: 1px solid #606060;
|
||||||
|
color: #d5c4a1;
|
||||||
|
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ h2 {
|
|||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #3f9da1;
|
color: #fabd2f;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
@ -70,7 +70,7 @@ button {
|
|||||||
background: #202020;
|
background: #202020;
|
||||||
color: #d5c4a1;
|
color: #d5c4a1;
|
||||||
padding: 8px 32px;
|
padding: 8px 32px;
|
||||||
border: 1px solid #3a3a3a;
|
border: 1px solid #535353;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ h2 {
|
|||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #3f9da1;
|
color: #fabd2f;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
@ -70,7 +70,7 @@ button {
|
|||||||
background: #202020;
|
background: #202020;
|
||||||
color: #d5c4a1;
|
color: #d5c4a1;
|
||||||
padding: 8px 32px;
|
padding: 8px 32px;
|
||||||
border: 1px solid #3a3a3a;
|
border: 1px solid #535353;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,35 @@
|
|||||||
export class UI {
|
export class UI {
|
||||||
constructor() {
|
constructor() {//{{{
|
||||||
document.getElementById('button-run').
|
document.getElementById('button-run').
|
||||||
addEventListener('click', evt=>evt.preventDefault())
|
addEventListener('click', evt => evt.preventDefault())
|
||||||
|
|
||||||
document.addEventListener('keydown', evt=>this.keyHandler(evt))
|
document.addEventListener('keydown', evt => this.keyHandler(evt))
|
||||||
}
|
|
||||||
setTrigger(t) {
|
document.querySelector('input[name="name"]').focus()
|
||||||
|
|
||||||
|
this.datapoints = []
|
||||||
|
}//}}}
|
||||||
|
render() {//{{{
|
||||||
|
document.querySelectorAll('.datapoints .datapoint').forEach(el => el.remove());
|
||||||
|
|
||||||
|
const datapoints = document.querySelector('.datapoints')
|
||||||
|
|
||||||
|
let html = Object.keys(this.trigger.datapoints).sort().map(dpName => {
|
||||||
|
const dp = this.trigger.datapoints[dpName]
|
||||||
|
return `
|
||||||
|
<div class="datapoint name"><b>${dp.Name}</b></div>
|
||||||
|
<div class="datapoint value">${dp.LastDatapointValue.TemplateValue}</div>
|
||||||
|
`
|
||||||
|
}).join('')
|
||||||
|
datapoints.innerHTML += html
|
||||||
|
}//}}}
|
||||||
|
setTrigger(t) {//{{{
|
||||||
this.trigger = t
|
this.trigger = t
|
||||||
}
|
}//}}}
|
||||||
run() {
|
run() {//{{{
|
||||||
this.trigger.run()
|
this.trigger.run()
|
||||||
}
|
}//}}}
|
||||||
keyHandler(evt) {
|
keyHandler(evt) {//{{{
|
||||||
if (!(evt.altKey && evt.shiftKey))
|
if (!(evt.altKey && evt.shiftKey))
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -24,18 +42,72 @@ export class UI {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
document.getElementById('form-trigger').submit()
|
this.update()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}//}}}
|
||||||
|
addDatapoint() {//{{{
|
||||||
|
const dlg = document.getElementById('dlg-datapoints')
|
||||||
|
const datalist = document.getElementById('list-datapoints')
|
||||||
|
dlg.showModal()
|
||||||
|
|
||||||
|
fetch('/datapoints?format=json')
|
||||||
|
.then(data => data.json())
|
||||||
|
.then(json => {
|
||||||
|
this.datapoints = json
|
||||||
|
|
||||||
|
let html = ''
|
||||||
|
this.datapoints.forEach(dp => {
|
||||||
|
html += `<option value="${dp.Name}">`
|
||||||
|
})
|
||||||
|
datalist.innerHTML = html
|
||||||
|
})
|
||||||
|
.catch(err => alert(err))
|
||||||
|
}//}}}
|
||||||
|
chooseDatapoint() {//{{{
|
||||||
|
const dlg = document.getElementById('dlg-datapoints')
|
||||||
|
const datapoint = document.getElementById('datapoint').value
|
||||||
|
const dp = this.datapoints.find(dp => dp.Name == datapoint)
|
||||||
|
|
||||||
|
if (dp === undefined) {
|
||||||
|
alert('Invalid datapoint')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.trigger.addDatapoint(dp)
|
||||||
|
dlg.close()
|
||||||
|
this.render()
|
||||||
|
}//}}}
|
||||||
|
update() {//{{{
|
||||||
|
const form = document.getElementById('form-trigger')
|
||||||
|
var formData = new FormData(form)
|
||||||
|
Object.keys(this.trigger.datapoints).forEach(name => formData.append("datapoints[]", name))
|
||||||
|
fetch(form.action, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.redirected) {
|
||||||
|
location.href = resp.url
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return resp.json()
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json)
|
||||||
|
alert(json.Error)
|
||||||
|
})
|
||||||
|
.catch(err => alert(err))
|
||||||
|
}//}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Trigger {
|
export class Trigger {
|
||||||
constructor(id, name) {
|
constructor(id, name, datapoints) {//{{{
|
||||||
this.id = id
|
this.id = id
|
||||||
this.name = name
|
this.name = name
|
||||||
}
|
this.datapoints = datapoints
|
||||||
run() {
|
}//}}}
|
||||||
|
run() {//{{{
|
||||||
const result = document.getElementById('run-result')
|
const result = document.getElementById('run-result')
|
||||||
const classes = result.classList
|
const classes = result.classList
|
||||||
const expr = document.getElementById('expr').value
|
const expr = document.getElementById('expr').value
|
||||||
@ -59,5 +131,8 @@ export class Trigger {
|
|||||||
result.innerText = json.Output
|
result.innerText = json.Output
|
||||||
})
|
})
|
||||||
.catch(err => alert(err))
|
.catch(err => alert(err))
|
||||||
}
|
}//}}}
|
||||||
|
addDatapoint(dp) {//{{{
|
||||||
|
this.datapoints[dp.Name] = dp
|
||||||
|
}//}}}
|
||||||
}
|
}
|
||||||
|
@ -71,17 +71,22 @@
|
|||||||
.section {
|
.section {
|
||||||
margin: 8px 16px;
|
margin: 8px 16px;
|
||||||
|
|
||||||
|
.create {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content min-content;
|
||||||
|
grid-gap: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.new {
|
||||||
|
font-weight: @bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&>.name {
|
&>.name {
|
||||||
font-weight: 500;
|
font-weight: @bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.triggers {
|
.triggers {
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger {
|
.trigger {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
@ -94,10 +99,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: @color4;
|
color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
background: @bg2;
|
||||||
|
border: 1px solid lighten(@bg2, 25%);
|
||||||
|
color: @text1;
|
||||||
|
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
@ -59,7 +59,7 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: @color4;
|
color: @color2;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -96,7 +96,7 @@ button {
|
|||||||
background: @bg2;
|
background: @bg2;
|
||||||
color: @text1;
|
color: @text1;
|
||||||
padding: 8px 32px;
|
padding: 8px 32px;
|
||||||
border: 1px solid lighten(@bg2, 10%);
|
border: 1px solid lighten(@bg2, 20%);
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
@import "theme.less";
|
@import "theme.less";
|
||||||
|
|
||||||
|
#dlg-datapoints {
|
||||||
|
}
|
||||||
|
|
||||||
.widgets {
|
.widgets {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
|
41
trigger.go
41
trigger.go
@ -4,6 +4,7 @@ import (
|
|||||||
// External
|
// External
|
||||||
we "git.gibonuddevalla.se/go/wrappederror"
|
we "git.gibonuddevalla.se/go/wrappederror"
|
||||||
"github.com/expr-lang/expr"
|
"github.com/expr-lang/expr"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -19,9 +20,6 @@ type Trigger struct {
|
|||||||
Datapoints []string
|
Datapoints []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Foo() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func TriggersRetrieve() (areas []Area, err error) { // {{{
|
func TriggersRetrieve() (areas []Area, err error) { // {{{
|
||||||
areas = []Area{}
|
areas = []Area{}
|
||||||
|
|
||||||
@ -130,21 +128,50 @@ func (t *Trigger) Update() (err error) { // {{{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("FOO", "trigger", t)
|
if t.Datapoints == nil {
|
||||||
|
t.Datapoints = []string{}
|
||||||
|
}
|
||||||
|
jsonDatapoints, _ := json.Marshal(t.Datapoints)
|
||||||
|
if t.ID == 0 {
|
||||||
|
_, err = service.Db.Conn.Exec(`
|
||||||
|
INSERT INTO "trigger"(name, section_id, expression, datapoints)
|
||||||
|
VALUES($1, $2, $3, $4)
|
||||||
|
`,
|
||||||
|
t.Name,
|
||||||
|
t.SectionID,
|
||||||
|
t.Expression,
|
||||||
|
jsonDatapoints,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
_, err = service.Db.Conn.Exec(`
|
_, err = service.Db.Conn.Exec(`
|
||||||
UPDATE "trigger"
|
UPDATE "trigger"
|
||||||
SET
|
SET
|
||||||
name=$2,
|
name=$2,
|
||||||
expression=$3
|
expression=$3,
|
||||||
|
datapoints=$4
|
||||||
WHERE
|
WHERE
|
||||||
id=$1
|
id=$1
|
||||||
`,
|
`,
|
||||||
t.ID,
|
t.ID,
|
||||||
t.Name,
|
t.Name,
|
||||||
t.Expression,
|
t.Expression,
|
||||||
|
jsonDatapoints,
|
||||||
)
|
)
|
||||||
if err != nil {
|
}
|
||||||
err = we.Wrap(err)
|
|
||||||
|
if pqErr, ok := err.(*pq.Error); ok {
|
||||||
|
err = we.Wrap(err).WithData(
|
||||||
|
struct {
|
||||||
|
Trigger *Trigger
|
||||||
|
PostgresCode pq.ErrorCode
|
||||||
|
PostgresMsg string
|
||||||
|
}{
|
||||||
|
t,
|
||||||
|
pqErr.Code,
|
||||||
|
pqErr.Code.Name(),
|
||||||
|
})
|
||||||
|
} else if err != nil {
|
||||||
|
err = we.Wrap(err).WithData(t)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} // }}}
|
} // }}}
|
||||||
|
@ -6,24 +6,31 @@
|
|||||||
let trigger = new Trigger(
|
let trigger = new Trigger(
|
||||||
{{ .Data.Trigger.ID }},
|
{{ .Data.Trigger.ID }},
|
||||||
'{{ .Data.Trigger.Name }}',
|
'{{ .Data.Trigger.Name }}',
|
||||||
|
{{ .Data.Datapoints }},
|
||||||
)
|
)
|
||||||
_ui.setTrigger(trigger)
|
_ui.setTrigger(trigger)
|
||||||
|
_ui.render()
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/{{ .VERSION }}/trigger_edit.css">
|
<link rel="stylesheet" type="text/css" href="/css/{{ .VERSION }}/trigger_edit.css">
|
||||||
|
|
||||||
{{ block "page_label" . }}{{end}}
|
{{ block "page_label" . }}{{end}}
|
||||||
|
|
||||||
|
<dialog id="dlg-datapoints">
|
||||||
|
<input list="list-datapoints" id="datapoint">
|
||||||
|
<datalist id="list-datapoints"></datalist>
|
||||||
|
<button onclick="_ui.chooseDatapoint()">OK</button>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
<form id="form-trigger" action="/trigger/update/{{ .Data.Trigger.ID }}" method="post">
|
<form id="form-trigger" action="/trigger/update/{{ .Data.Trigger.ID }}" method="post">
|
||||||
|
<input type="hidden" name="sectionID" value="{{ .Data.Trigger.SectionID }}">
|
||||||
<div id="widgets" class="widgets">
|
<div id="widgets" class="widgets">
|
||||||
<div class="label">Name</div>
|
<div class="label">Name</div>
|
||||||
<div><input type="text" name="name" value="{{ .Data.Trigger.Name }}"></div>
|
<div><input type="text" name="name" value="{{ .Data.Trigger.Name }}"></div>
|
||||||
|
|
||||||
<div class="label">Datapoints</div>
|
<div class="label">Datapoints</div>
|
||||||
<div class="datapoints" style="margin-top: 4px">
|
<div class="datapoints" style="margin-top: 4px">
|
||||||
{{ range .Data.Datapoints }}
|
<div><a onclick="_ui.addDatapoint()">Add</a></div>
|
||||||
<div class="datapoint name"><b>{{ .Name }}</b></div>
|
<div></div>
|
||||||
<div class="datapoint value">{{ .LastDatapointValue.Value }}</div>
|
|
||||||
{{ end }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="label">Expression</div>
|
<div class="label">Expression</div>
|
||||||
@ -31,10 +38,11 @@
|
|||||||
|
|
||||||
<div></div>
|
<div></div>
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<button id="button-update">Update</button>
|
<button id="button-update" onclick="_ui.update(); return false">{{ if eq .Data.Trigger.ID 0 }}Create{{ else }}Update{{ end }}</button>
|
||||||
<button id="button-run" onclick="window._ui.run(); return false">Test</button>
|
<button id="button-run" onclick="window._ui.run(); return false">Test</button>
|
||||||
<div id="run-result"></div>
|
<div id="run-result"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -9,7 +9,10 @@
|
|||||||
<div class="name">{{ .Name }}</div>
|
<div class="name">{{ .Name }}</div>
|
||||||
{{ range .SortedSections }}
|
{{ range .SortedSections }}
|
||||||
<div class="section">
|
<div class="section">
|
||||||
|
<div class="create">
|
||||||
<div class="name">{{ .Name }}</div>
|
<div class="name">{{ .Name }}</div>
|
||||||
|
<div class="new"><a href="/trigger/edit/0/{{ .ID }}">+</a></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="triggers">
|
<div class="triggers">
|
||||||
{{ range .SortedTriggers }}
|
{{ range .SortedTriggers }}
|
||||||
|
Loading…
Reference in New Issue
Block a user