Refactored time selecting
This commit is contained in:
parent
02794e9629
commit
cd8765e0f2
29
helper.go
29
helper.go
@ -5,8 +5,9 @@ import (
|
|||||||
werr "git.gibonuddevalla.se/go/wrappederror"
|
werr "git.gibonuddevalla.se/go/wrappederror"
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
"time"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rxpTimezone *regexp.Regexp
|
var rxpTimezone *regexp.Regexp
|
||||||
@ -15,7 +16,7 @@ func init() {
|
|||||||
rxpTimezone = regexp.MustCompile(`(\d\d)(\d\d)$`)
|
rxpTimezone = regexp.MustCompile(`(\d\d)(\d\d)$`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringToTime(strTime string) (t time.Time, err error) {// {{{
|
func stringToTime(strTime string) (t time.Time, err error) { // {{{
|
||||||
// `date` command %z gives timezone like +0200 instead of +02:00.
|
// `date` command %z gives timezone like +0200 instead of +02:00.
|
||||||
// This can easily be fixed here, not requiring all scripts to be fixed.
|
// This can easily be fixed here, not requiring all scripts to be fixed.
|
||||||
t, err = time.Parse(time.RFC3339, strTime)
|
t, err = time.Parse(time.RFC3339, strTime)
|
||||||
@ -37,8 +38,8 @@ func stringToTime(strTime string) (t time.Time, err error) {// {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}// }}}
|
} // }}}
|
||||||
func parseHTMLDateTime(str string, dflt time.Time) (t time.Time, err error) {
|
func parseHTMLDateTime(str string, dflt time.Time) (t time.Time, err error) { // {{{
|
||||||
// Browser sending 2024-06-27T10:43 (16 characters) when seconds is 00.
|
// Browser sending 2024-06-27T10:43 (16 characters) when seconds is 00.
|
||||||
if len(str) == 16 {
|
if len(str) == 16 {
|
||||||
str += ":00"
|
str += ":00"
|
||||||
@ -52,4 +53,24 @@ func parseHTMLDateTime(str string, dflt time.Time) (t time.Time, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
func applyTimeOffset(t time.Time, duration time.Duration, amountStr string) time.Time { // {{{
|
||||||
|
amount, err := strconv.Atoi(amountStr)
|
||||||
|
if err != nil {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.Add(duration * time.Duration(amount))
|
||||||
|
} // }}}
|
||||||
|
func presetTimeInterval(duration time.Duration, presetStr string, timeFrom, timeTo *time.Time) () {
|
||||||
|
if presetStr == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
presetTime, _ := strconv.Atoi(presetStr)
|
||||||
|
(*timeFrom) = now.Add(duration * -1 * time.Duration(presetTime))
|
||||||
|
(*timeTo) = now
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
34
main.go
34
main.go
@ -717,25 +717,23 @@ func pageDatapointValues(w http.ResponseWriter, r *http.Request, _ *session.T) {
|
|||||||
|
|
||||||
var timeFrom, timeTo time.Time
|
var timeFrom, timeTo time.Time
|
||||||
yesterday := time.Now().Add(time.Duration(-24 * time.Hour))
|
yesterday := time.Now().Add(time.Duration(-24 * time.Hour))
|
||||||
|
|
||||||
timeFrom, err = parseHTMLDateTime(r.URL.Query().Get("f"), yesterday)
|
timeFrom, err = parseHTMLDateTime(r.URL.Query().Get("f"), yesterday)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, werr.Wrap(err).Log())
|
httpError(w, werr.Wrap(err).WithData(r.URL.Query().Get("f")).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
timeTo, err = parseHTMLDateTime(r.URL.Query().Get("t"), time.Now())
|
timeTo, err = parseHTMLDateTime(r.URL.Query().Get("t"), time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(w, werr.Wrap(err).Log())
|
httpError(w, werr.Wrap(err).WithData(r.URL.Query().Get("t")).Log())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
presetTimeInterval(time.Hour, r.URL.Query().Get("preset"), &timeFrom, &timeTo)
|
||||||
|
|
||||||
// Apply an optionally set offset (in seconds).
|
// Apply an optionally set offset (in seconds).
|
||||||
var offsetTime int
|
timeFrom = applyTimeOffset(timeFrom, time.Second, r.URL.Query().Get("offset-time"))
|
||||||
offsetTimeStr := r.URL.Query().Get("offset-time")
|
timeTo = applyTimeOffset(timeTo, time.Second, r.URL.Query().Get("offset-time"))
|
||||||
offsetTime, err = strconv.Atoi(offsetTimeStr)
|
|
||||||
timeFrom = timeFrom.Add(time.Second * time.Duration(offsetTime))
|
|
||||||
timeTo = timeTo.Add(time.Second * time.Duration(offsetTime))
|
|
||||||
|
|
||||||
// Fetch data point values according to the times.
|
// Fetch data point values according to the times.
|
||||||
var values []DatapointValue
|
var values []DatapointValue
|
||||||
@ -1216,25 +1214,11 @@ func pageNotifications(w http.ResponseWriter, r *http.Request, _ *session.T) { /
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var presetTime int
|
presetTimeInterval(time.Hour, r.URL.Query().Get("preset"), &timeFrom, &timeTo)
|
||||||
now := time.Now()
|
|
||||||
presetStr := r.URL.Query().Get("preset")
|
|
||||||
if presetStr != "" {
|
|
||||||
presetTime, err = strconv.Atoi(presetStr)
|
|
||||||
if err != nil {
|
|
||||||
pageError(w, "/notifications", werr.Wrap(err).WithData(presetStr).Log())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
timeFrom = now.Add(time.Hour * -1 * time.Duration(presetTime))
|
|
||||||
timeTo = now
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply an optionally set offset (in seconds).
|
// Apply an optionally set offset (in seconds).
|
||||||
var offsetTime int
|
timeFrom = applyTimeOffset(timeFrom, time.Second, r.URL.Query().Get("offset-time"))
|
||||||
offsetTimeStr := r.URL.Query().Get("offset-time")
|
timeTo = applyTimeOffset(timeTo, time.Second, r.URL.Query().Get("offset-time"))
|
||||||
offsetTime, err = strconv.Atoi(offsetTimeStr)
|
|
||||||
timeFrom = timeFrom.Add(time.Second * time.Duration(offsetTime))
|
|
||||||
timeTo = timeTo.Add(time.Second * time.Duration(offsetTime))
|
|
||||||
|
|
||||||
nss, err := notificationsSent(timeFrom, timeTo)
|
nss, err := notificationsSent(timeFrom, timeTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -48,7 +48,7 @@ func notificationsSent(from, to time.Time) (nss []NotificationSend, err error) {
|
|||||||
n.prio,
|
n.prio,
|
||||||
n.service,
|
n.service,
|
||||||
|
|
||||||
COALESCE(t.name, '') AS trigger_name,
|
COALESCE(t.name, '[NODATA]') AS trigger_name,
|
||||||
|
|
||||||
ns.id,
|
ns.id,
|
||||||
ns.uuid,
|
ns.uuid,
|
||||||
|
@ -85,8 +85,8 @@
|
|||||||
}
|
}
|
||||||
.value-selector button {
|
.value-selector button {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
align-self: end;
|
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
.graph {
|
.graph {
|
||||||
width: 99%;
|
width: 99%;
|
||||||
@ -98,9 +98,23 @@
|
|||||||
}
|
}
|
||||||
.time-offset {
|
.time-offset {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, min-content);
|
grid-template-columns: min-content repeat(3, min-content);
|
||||||
gap: 6px 12px;
|
grid-gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
margin-top: 8px;
|
}
|
||||||
|
.time-offset .header-1 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
.time-offset .header-2 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
grid-column: 2 / -1;
|
||||||
|
}
|
||||||
|
.time-offset .preset {
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-self: start;
|
||||||
|
padding-right: 32px;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content min-content;
|
grid-template-columns: min-content min-content;
|
||||||
grid-gap: 6px 16px;
|
grid-gap: 6px 16px;
|
||||||
padding: 16px;
|
|
||||||
border: 1px solid #7bb8eb;
|
|
||||||
width: min-content;
|
width: min-content;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,8 @@
|
|||||||
}
|
}
|
||||||
.value-selector button {
|
.value-selector button {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
align-self: end;
|
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
.graph {
|
.graph {
|
||||||
width: 99%;
|
width: 99%;
|
||||||
@ -98,9 +98,23 @@
|
|||||||
}
|
}
|
||||||
.time-offset {
|
.time-offset {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, min-content);
|
grid-template-columns: min-content repeat(3, min-content);
|
||||||
gap: 6px 12px;
|
grid-gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
margin-top: 8px;
|
}
|
||||||
|
.time-offset .header-1 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
.time-offset .header-2 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
grid-column: 2 / -1;
|
||||||
|
}
|
||||||
|
.time-offset .preset {
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-self: start;
|
||||||
|
padding-right: 32px;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content min-content;
|
grid-template-columns: min-content min-content;
|
||||||
grid-gap: 6px 16px;
|
grid-gap: 6px 16px;
|
||||||
padding: 16px;
|
|
||||||
border: 1px solid #777;
|
|
||||||
width: min-content;
|
width: min-content;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
function preset(hours) {
|
||||||
|
const inputPreset = document.querySelector('input[name="preset"]')
|
||||||
|
inputPreset.value = hours
|
||||||
|
inputPreset.form.submit()
|
||||||
|
}
|
||||||
|
|
||||||
function offsetTime(seconds) {
|
function offsetTime(seconds) {
|
||||||
const el = document.getElementById('offset-time')
|
const inputPreset = document.querySelector('input[name="offset-time"]')
|
||||||
el.value = seconds
|
inputPreset.value = seconds
|
||||||
el.form.submit()
|
inputPreset.form.submit()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Graph {
|
class Graph {
|
||||||
|
@ -102,8 +102,8 @@
|
|||||||
|
|
||||||
button {
|
button {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
align-self: end;
|
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +119,27 @@
|
|||||||
|
|
||||||
.time-offset {
|
.time-offset {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, min-content);
|
grid-template-columns: min-content repeat(3, min-content);
|
||||||
gap: 6px 12px;
|
grid-gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
margin-top: 8px;
|
|
||||||
|
.header-1 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-2 {
|
||||||
|
font-weight: bold;
|
||||||
|
justify-self: start;
|
||||||
|
grid-column: ~"2 / -1";
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset {
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-self: start;
|
||||||
|
padding-right: 32px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
grid-template-columns: min-content min-content;
|
grid-template-columns: min-content min-content;
|
||||||
grid-gap: 6px 16px;
|
grid-gap: 6px 16px;
|
||||||
|
|
||||||
padding: 16px;
|
|
||||||
border: 1px solid @text3;
|
|
||||||
width: min-content;
|
width: min-content;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
//grid-column: ~"1 / -1";
|
|
||||||
width: 100px;
|
width: 100px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
{{ block "page_label" . }}{{end}}
|
{{ block "page_label" . }}{{end}}
|
||||||
|
|
||||||
<form action="/datapoint/values/{{ .Data.Datapoint.ID }}" method="get" style="margin-top: -16px">
|
<form action="/datapoint/values/{{ .Data.Datapoint.ID }}" method="get" style="margin-top: -16px">
|
||||||
<input type="hidden" name="offset-time" id="offset-time" value=0>
|
<input type="hidden" name="preset" value="">
|
||||||
|
<input type="hidden" name="offset-time" value=0>
|
||||||
|
|
||||||
{{ if eq .Data.Datapoint.Datatype "INT" }}
|
{{ if eq .Data.Datapoint.Datatype "INT" }}
|
||||||
<div>
|
<div>
|
||||||
@ -25,17 +26,32 @@
|
|||||||
<input name="t" type="datetime-local" step="1" value="{{ .Data.TimeTo }}">
|
<input name="t" type="datetime-local" step="1" value="{{ .Data.TimeTo }}">
|
||||||
|
|
||||||
<div class="time-offset">
|
<div class="time-offset">
|
||||||
|
<div class="header-1">Presets</div>
|
||||||
|
<div class="header-2">Offsets</div>
|
||||||
|
|
||||||
|
<div class="preset"><a href="#" onclick="preset(1)">Last hour</a></div>
|
||||||
|
|
||||||
<div><a href="#" onclick="offsetTime(-3600)">◀</a></div>
|
<div><a href="#" onclick="offsetTime(-3600)">◀</a></div>
|
||||||
<div>Hour</div>
|
<div>Hour</div>
|
||||||
<div><a href="#" onclick="offsetTime(3600)">▶</a></div>
|
<div><a href="#" onclick="offsetTime(3600)">▶</a></div>
|
||||||
|
|
||||||
|
<div class="preset"><a href="#" onclick="preset(24)">Last 24 hours</a></div>
|
||||||
|
|
||||||
<div><a href="#" onclick="offsetTime(-86400)">◀</a></div>
|
<div><a href="#" onclick="offsetTime(-86400)">◀</a></div>
|
||||||
<div>Day</div>
|
<div>Day</div>
|
||||||
<div><a href="#" onclick="offsetTime(86400)">▶</a></div>
|
<div><a href="#" onclick="offsetTime(86400)">▶</a></div>
|
||||||
|
|
||||||
<div><a href="#" onclick="offsetTime(-604800)">◀</a></div>
|
<div class="preset"><a href="#" onclick="preset(24 * 7)">Last 7 days</a></div>
|
||||||
|
|
||||||
|
<div><a href="#" onclick="offsetTime(-7 * 86400)">◀</a></div>
|
||||||
<div>Week</div>
|
<div>Week</div>
|
||||||
<div><a href="#" onclick="offsetTime(604800)">▶</a></div>
|
<div><a href="#" onclick="offsetTime(7 * 86400)">▶</a></div>
|
||||||
|
|
||||||
|
<div class="preset"><a href="#" onclick="preset(24 * 31)">Last 31 days</a></div>
|
||||||
|
|
||||||
|
<div><a href="#" onclick="offsetTime(-31 * 86400)">◀</a></div>
|
||||||
|
<div>Month</div>
|
||||||
|
<div><a href="#" onclick="offsetTime(31 * 86400)">▶</a></div>
|
||||||
</div>
|
</div>
|
||||||
<button>OK</button>
|
<button>OK</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<div>Week</div>
|
<div>Week</div>
|
||||||
<div><a href="#" onclick="offsetTime(7 * 86400)">▶</a></div>
|
<div><a href="#" onclick="offsetTime(7 * 86400)">▶</a></div>
|
||||||
|
|
||||||
<div class="preset"><a href="#" onclick="preset(24 * 7 * 31)">Last 31 days</a></div>
|
<div class="preset"><a href="#" onclick="preset(24 * 31)">Last 31 days</a></div>
|
||||||
|
|
||||||
<div><a href="#" onclick="offsetTime(-31 * 86400)">◀</a></div>
|
<div><a href="#" onclick="offsetTime(-31 * 86400)">◀</a></div>
|
||||||
<div>Month</div>
|
<div>Month</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user