feat(ui): Add support for buttons below header (#106)

This commit is contained in:
TwiN
2022-04-25 20:20:32 -04:00
parent dcb997f501
commit 9ede992e4e
11 changed files with 97 additions and 15 deletions

View File

@ -53,7 +53,14 @@ maintenance:
duration: 4h
every: [Monday, Thursday]
ui:
title: Test
title: T
header: H
link: https://example.org
buttons:
- name: "Home"
link: "https://example.org"
- name: "Status page"
link: "https://status.example.org"
endpoints:
- name: website
url: https://twin.sh/health
@ -88,8 +95,8 @@ endpoints:
if config.Storage == nil || config.Storage.Path != file || config.Storage.Type != storage.TypeSQLite {
t.Error("expected storage to be set to sqlite, got", config.Storage)
}
if config.UI == nil || config.UI.Title != "Test" {
t.Error("Expected Config.UI.Title to be Test")
if config.UI == nil || config.UI.Title != "T" || config.UI.Header != "H" || config.UI.Link != "https://example.org" || len(config.UI.Buttons) != 2 || config.UI.Buttons[0].Name != "Home" || config.UI.Buttons[0].Link != "https://example.org" || config.UI.Buttons[1].Name != "Status page" || config.UI.Buttons[1].Link != "https://status.example.org" {
t.Error("expected ui to be set to T, H, https://example.org, 2 buttons, Home and Status page, got", config.UI)
}
if mc := config.Maintenance; mc == nil || mc.Start != "00:00" || !mc.IsEnabled() || mc.Duration != 4*time.Hour || len(mc.Every) != 2 {
t.Error("Expected Config.Maintenance to be configured properly")

View File

@ -2,6 +2,7 @@ package ui
import (
"bytes"
"errors"
"html/template"
)
@ -16,14 +17,31 @@ var (
// StaticFolder is the path to the location of the static folder from the root path of the project
// The only reason this is exposed is to allow running tests from a different path than the root path of the project
StaticFolder = "./web/static"
ErrButtonValidationFailed = errors.New("invalid button configuration: missing required name or link")
)
// Config is the configuration for the UI of Gatus
type Config struct {
Title string `yaml:"title,omitempty"` // Title of the page
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
Title string `yaml:"title,omitempty"` // Title of the page
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header
}
// Button is the configuration for a button on the UI
type Button struct {
Name string `yaml:"name,omitempty"` // Name is the text to display on the button
Link string `yaml:"link,omitempty"` // Link to open when the button is clicked.
}
// Validate validates the button configuration
func (btn *Button) Validate() error {
if len(btn.Name) == 0 || len(btn.Link) == 0 {
return ErrButtonValidationFailed
}
return nil
}
// GetDefaultConfig returns a Config struct with the default values
@ -47,6 +65,12 @@ func (cfg *Config) ValidateAndSetDefaults() error {
if len(cfg.Header) == 0 {
cfg.Header = defaultLink
}
for _, btn := range cfg.Buttons {
if err := btn.Validate(); err != nil {
return err
}
}
// Validate that the template works
t, err := template.ParseFiles(StaticFolder + "/index.html")
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package ui
import (
"strconv"
"testing"
)
@ -26,6 +27,45 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
}
}
func TestButton_Validate(t *testing.T) {
scenarios := []struct {
Name, Link string
ExpectedError error
}{
{
Name: "",
Link: "",
ExpectedError: ErrButtonValidationFailed,
},
{
Name: "",
Link: "link",
ExpectedError: ErrButtonValidationFailed,
},
{
Name: "name",
Link: "",
ExpectedError: ErrButtonValidationFailed,
},
{
Name: "name",
Link: "link",
ExpectedError: nil,
},
}
for i, scenario := range scenarios {
t.Run(strconv.Itoa(i)+"_"+scenario.Name+"_"+scenario.Link, func(t *testing.T) {
button := &Button{
Name: scenario.Name,
Link: scenario.Link,
}
if err := button.Validate(); err != scenario.ExpectedError {
t.Errorf("expected error %v, got %v", scenario.ExpectedError, err)
}
})
}
}
func TestGetDefaultConfig(t *testing.T) {
defaultConfig := GetDefaultConfig()
if defaultConfig.Title != defaultTitle {