added 'schedules' page, allowing quick enabling/disabling of schedule filters
This commit is contained in:
parent
a9790cd64d
commit
9938af6a3b
4 changed files with 142 additions and 16 deletions
|
@ -3,23 +3,27 @@ package models
|
|||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
type FilterID uint
|
||||
type FilterType string
|
||||
type Filter struct {
|
||||
ID FilterID `form:"filter_id" yaml:"filter_id" json:"filter_id"`
|
||||
WatchID WatchID `form:"filter_watch_id" gorm:"index" yaml:"filter_watch_id" json:"filter_watch_id" binding:"required"`
|
||||
Name string `form:"filter_name" gorm:"index" yaml:"filter_name" json:"filter_name" binding:"required" validate:"min=1"`
|
||||
X int `form:"x" yaml:"x" json:"x" validate:"default=0"`
|
||||
Y int `form:"y" yaml:"y" json:"y" validate:"default=0"`
|
||||
Type FilterType `form:"filter_type" yaml:"filter_type" json:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring math store condition cron"`
|
||||
Var1 string `form:"var1" yaml:"var1" json:"var1" binding:"required"`
|
||||
Var2 *string `form:"var2" yaml:"var2" json:"var2"`
|
||||
Parents []*Filter `gorm:"-:all"`
|
||||
Children []*Filter `gorm:"-:all"`
|
||||
Results []string `gorm:"-:all"`
|
||||
Logs []string `gorm:"-:all"`
|
||||
ID FilterID `form:"filter_id" yaml:"filter_id" json:"filter_id"`
|
||||
WatchID WatchID `form:"filter_watch_id" gorm:"index" yaml:"filter_watch_id" json:"filter_watch_id" binding:"required"`
|
||||
Name string `form:"filter_name" gorm:"index" yaml:"filter_name" json:"filter_name" binding:"required" validate:"min=1"`
|
||||
X int `form:"x" yaml:"x" json:"x" validate:"default=0"`
|
||||
Y int `form:"y" yaml:"y" json:"y" validate:"default=0"`
|
||||
Type FilterType `form:"filter_type" yaml:"filter_type" json:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring math store condition cron"`
|
||||
Var1 string `form:"var1" yaml:"var1" json:"var1" binding:"required"`
|
||||
Var2 *string `form:"var2" yaml:"var2" json:"var2"`
|
||||
Parents []*Filter `gorm:"-:all"`
|
||||
Children []*Filter `gorm:"-:all"`
|
||||
Results []string `gorm:"-:all"`
|
||||
Logs []string `gorm:"-:all"`
|
||||
CronEntry *cron.Entry `gorm:"-:all"`
|
||||
Enabled string `gorm:"-:all"` // lazy fix for not being able to pointer deref in golang template....
|
||||
}
|
||||
|
||||
func (filter *Filter) Log(v ...any) {
|
||||
|
|
|
@ -18,15 +18,12 @@
|
|||
|
||||
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Go Watch</a>
|
||||
<a class="navbar-brand" href="{{.urlPrefix}}">Go Watch</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="{{.urlPrefix}}">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}notifiers/view">Notifiers</a>
|
||||
</li>
|
||||
|
@ -36,6 +33,9 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}backup/view">Backups</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}schedules/view">Schedules</a>
|
||||
</li>
|
||||
{{ template "navbar" .}}
|
||||
</ul>
|
||||
<div class="d-flex">
|
||||
|
|
49
web/templates/schedules.html
Normal file
49
web/templates/schedules.html
Normal file
|
@ -0,0 +1,49 @@
|
|||
{{define "title"}}
|
||||
GoWatch
|
||||
{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<form action="{{.urlPrefix}}schedules/update" method="POST">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>WatchID</th>
|
||||
<th>Watch</th>
|
||||
<th>Schedule</th>
|
||||
<th>Last</th>
|
||||
<th>Next</th>
|
||||
<th>Enabled</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range $watch, $scheduleFilters := .watchSchedules }}
|
||||
{{ range $i, $scheduleFilter := $scheduleFilters }}
|
||||
<tr>
|
||||
<td class="h3">{{ $watch.ID }}</td>
|
||||
<td class="h3">{{ $watch.Name }}</td>
|
||||
<td class="h3">{{ $scheduleFilter.Name }}</td>
|
||||
{{ if $scheduleFilter.CronEntry }}
|
||||
<td class="h3">{{ $scheduleFilter.CronEntry.Prev.Format "2006-01-02 15:04:05" }}</td>
|
||||
<td class="h3">{{ $scheduleFilter.CronEntry.Next.Format "2006-01-02 15:04:05" }}</td>
|
||||
{{ else }}
|
||||
<td colspan="2" class="h3">Not scheduled</td>
|
||||
{{ end }}
|
||||
{{ if eq $scheduleFilter.Enabled "yes" }}
|
||||
<td class="h2">
|
||||
<input class="form-check-input" id="schedules_{{ $scheduleFilter.ID }}" type="checkbox" value="{{ $scheduleFilter.ID }}" name="schedules" checked>
|
||||
</td>
|
||||
{{ else }}
|
||||
<td class="h2">
|
||||
<input class="form-check-input" id="schedules_{{ $scheduleFilter.ID }}" type="checkbox" value="{{ $scheduleFilter.ID }}" name="schedules">
|
||||
</td>
|
||||
{{ end}}
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-primary btn-lg">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
{{end}}
|
73
web/web.go
73
web/web.go
|
@ -227,6 +227,9 @@ func (web *Web) initRouter() {
|
|||
gowatch.GET("notifiers/view", web.notifiersView)
|
||||
gowatch.POST("notifiers/test", web.notifiersTest)
|
||||
|
||||
gowatch.GET("schedules/view", web.schedulesView)
|
||||
gowatch.POST("schedules/update", web.schedulesUpdate)
|
||||
|
||||
gowatch.GET("backup/view", web.backupView)
|
||||
gowatch.GET("backup/create", web.backupCreate)
|
||||
gowatch.POST("backup/test", web.backupTest)
|
||||
|
@ -256,6 +259,8 @@ func (web *Web) initTemplates() {
|
|||
|
||||
web.templates.Add("notifiersView", template.Must(template.ParseFS(templatesFS, "base.html", "notifiers.html")))
|
||||
|
||||
web.templates.Add("schedulesView", template.Must(template.ParseFS(templatesFS, "base.html", "schedules.html")))
|
||||
|
||||
web.templates.Add("backupView", template.Must(template.ParseFS(templatesFS, "base.html", "backup/view.html")))
|
||||
web.templates.Add("backupTest", template.Must(template.ParseFS(templatesFS, "base.html", "backup/test.html")))
|
||||
web.templates.Add("backupRestore", template.Must(template.ParseFS(templatesFS, "base.html", "backup/restore.html")))
|
||||
|
@ -513,6 +518,74 @@ func (web *Web) notifiersTest(c *gin.Context) {
|
|||
c.Redirect(http.StatusSeeOther, web.urlPrefix+"notifiers/view")
|
||||
}
|
||||
|
||||
func (web *Web) schedulesView(c *gin.Context) {
|
||||
watches := []Watch{}
|
||||
web.db.Find(&watches)
|
||||
|
||||
watchMap := make(map[WatchID]*Watch, len(watches))
|
||||
for i := 0; i < len(watches); i++ {
|
||||
watchMap[watches[i].ID] = &watches[i]
|
||||
}
|
||||
|
||||
var filters []Filter
|
||||
web.db.Model(&Filter{}).Find(&filters, "type = 'cron'")
|
||||
|
||||
watchSchedules := make(map[*Watch][]*Filter)
|
||||
for i := range filters {
|
||||
filter := &filters[i]
|
||||
entryID, exists := web.cronWatch[filter.ID]
|
||||
|
||||
if exists {
|
||||
entry := web.cron.Entry(entryID)
|
||||
filter.CronEntry = &entry
|
||||
}
|
||||
filter.Enabled = *filter.Var2
|
||||
watch := watchMap[filter.WatchID]
|
||||
watchSchedules[watch] = append(watchSchedules[watch], filter)
|
||||
}
|
||||
c.HTML(http.StatusOK, "schedulesView", gin.H{
|
||||
"watchSchedules": watchSchedules,
|
||||
"urlPrefix": web.urlPrefix,
|
||||
})
|
||||
}
|
||||
|
||||
func (web *Web) schedulesUpdate(c *gin.Context) {
|
||||
scheduleStrings := c.PostFormArray("schedules")
|
||||
scheduleIDs := make(map[FilterID]bool)
|
||||
for _, scheduleString := range scheduleStrings {
|
||||
scheduleID, err := strconv.Atoi(scheduleString)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
scheduleIDs[FilterID(scheduleID)] = true
|
||||
}
|
||||
|
||||
var cronFilters []Filter
|
||||
web.db.Model(&Filter{}).Where("type = 'cron'").Find(&cronFilters)
|
||||
for i := range cronFilters {
|
||||
cronFilter := &cronFilters[i]
|
||||
entryID, exist := web.cronWatch[cronFilter.ID]
|
||||
_, checked := scheduleIDs[cronFilter.ID]
|
||||
if exist && !checked {
|
||||
web.cron.Remove(entryID)
|
||||
delete(web.cronWatch, cronFilter.ID)
|
||||
} else if !exist && checked {
|
||||
yes := "yes"
|
||||
cronFilter.Var2 = &yes
|
||||
web.addCronJobIfCronFilter(cronFilter, false)
|
||||
}
|
||||
}
|
||||
|
||||
if len(scheduleStrings) > 0 {
|
||||
web.db.Model(&Filter{}).Where("ID IN ?", scheduleStrings).Update("Var2", "yes")
|
||||
web.db.Model(&Filter{}).Where("ID NOT IN ?", scheduleStrings).Update("Var2", "no")
|
||||
} else {
|
||||
web.db.Model(&Filter{}).Where("TRUE").Update("Var2", "no")
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusSeeOther, web.urlPrefix+"schedules/view")
|
||||
}
|
||||
|
||||
// watchCreate (/watch/create) allows user to create a new watch
|
||||
// A name and an optional template can be picked
|
||||
func (web *Web) watchCreate(c *gin.Context) {
|
||||
|
|
Loading…
Add table
Reference in a new issue