feat: Monitor groups and chart information
Chart Release / chart (push) Successful in 15s
Server Deploy / deploy (push) Successful in 6m35s

This commit is contained in:
2026-08-24 10:30:23 +00:00
parent 83cdf92575
commit 2fab784ba7
9 changed files with 299 additions and 25 deletions
+7
View File
@@ -1085,6 +1085,10 @@
"enabled": {
"type": "boolean"
},
"group": {
"description": "Group is a display-only label. It buckets rows on the monitors page and\nhas no effect on scheduling, alerting or scope; an empty group means the\nmonitor is listed on its own under \"Ungrouped\".",
"type": "string"
},
"instance_id": {
"type": "string"
},
@@ -4208,6 +4212,9 @@
"enabled": {
"type": "boolean"
},
"group": {
"type": "string"
},
"interval_sec": {
"type": "integer"
},
+5 -1
View File
@@ -111,7 +111,7 @@ func getMonitor(c *gin.Context) {
// @Accept json
// @Produce json
// @Param id path string true "Monitor ID"
// @Param body body object{name=string,type=string,target=models.MonitorTarget,interval_sec=int,runner=string,retries=int,enabled=bool,channel_ids=[]string} true "Fields to update"
// @Param body body object{name=string,group=string,type=string,target=models.MonitorTarget,interval_sec=int,runner=string,retries=int,enabled=bool,channel_ids=[]string} true "Fields to update"
// @Success 204
// @Failure 400 {object} ErrorResponse
// @Failure 500 {object} ErrorResponse
@@ -121,6 +121,7 @@ func getMonitor(c *gin.Context) {
func updateMonitor(c *gin.Context) {
var body struct {
Name *string `json:"name"`
Group *string `json:"group"`
Type *string `json:"type"`
Target *models.MonitorTarget `json:"target"`
IntervalSec *int `json:"interval_sec"`
@@ -137,6 +138,9 @@ func updateMonitor(c *gin.Context) {
if body.Name != nil {
upd["name"] = *body.Name
}
if body.Group != nil {
upd["group"] = *body.Group
}
if body.Type != nil {
upd["type"] = *body.Type
}
+8 -4
View File
@@ -43,10 +43,14 @@ type MonitorState struct {
}
type Monitor struct {
ID bson.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
InstanceID string `bson:"instance_id" json:"instance_id"`
MonitorID string `bson:"monitor_id" json:"monitor_id"`
Name string `bson:"name" json:"name"`
ID bson.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
InstanceID string `bson:"instance_id" json:"instance_id"`
MonitorID string `bson:"monitor_id" json:"monitor_id"`
Name string `bson:"name" json:"name"`
// Group is a display-only label. It buckets rows on the monitors page and
// has no effect on scheduling, alerting or scope; an empty group means the
// monitor is listed on its own under "Ungrouped".
Group string `bson:"group,omitempty" json:"group,omitempty"`
Type string `bson:"type" json:"type"`
Target MonitorTarget `bson:"target" json:"target"`
IntervalSec int `bson:"interval_sec" json:"interval_sec"`
+33
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"log"
"strings"
"time"
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/checker"
@@ -21,6 +22,22 @@ func monCtx() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), 5*time.Second)
}
// MaxMonitorGroupLen bounds the display-only group label. It is a heading on
// the monitors page, not an identifier, so the cap is about the layout rather
// than storage.
const MaxMonitorGroupLen = 48
// normaliseGroup collapses the ways two people write the same group. Grouping
// is by exact string, so " Production " and "Production" must not become two
// headings.
func normaliseGroup(g string) (string, error) {
g = strings.Join(strings.Fields(g), " ")
if len([]rune(g)) > MaxMonitorGroupLen {
return "", fmt.Errorf("group must be %d characters or fewer", MaxMonitorGroupLen)
}
return g, nil
}
func SpecFor(m *models.Monitor) checker.Spec {
return checker.Spec{
Type: m.Type,
@@ -126,6 +143,11 @@ func CreateMonitor(instanceID string, m *models.Monitor) (*models.Monitor, error
if err := validateRunner(instanceID, m.Runner); err != nil {
return nil, err
}
group, err := normaliseGroup(m.Group)
if err != nil {
return nil, err
}
m.Group = group
m.InstanceID = instanceID
m.MonitorID = uuid.NewString()
m.CreatedAt = time.Now()
@@ -158,6 +180,17 @@ func UpdateMonitor(instanceID, monitorID string, upd bson.M) error {
return err
}
}
if raw, present := upd["group"]; present {
g, ok := raw.(string)
if !ok {
return fmt.Errorf("group must be a string")
}
group, err := normaliseGroup(g)
if err != nil {
return err
}
upd["group"] = group
}
if raw, present := upd["runner"]; present {
runner, ok := raw.(string)
if !ok {