Skip to content

Commit c39fcd4

Browse files
authored
Merge branch 'master' into ssh-key
2 parents 02090e9 + 5d626f2 commit c39fcd4

File tree

7 files changed

+155
-49
lines changed

7 files changed

+155
-49
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ If you want to test it locally, see [Docker](#docker).
263263
| `ui` | UI configuration. | `{}` |
264264
| `ui.title` | [Title of the document](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title). | `Health Dashboard ǀ Gatus` |
265265
| `ui.description` | Meta description for the page. | `Gatus is an advanced...`. |
266+
| `ui.dashboard-heading` | Dashboard title between header and endpoints | `Health Dashboard` |
267+
| `ui.dashboard-subheading` | Dashboard description between header and endpoints | `Monitor the health of your endpoints in real-time` |
266268
| `ui.header` | Header at the top of the dashboard. | `Gatus` |
267269
| `ui.logo` | URL to the logo to display. | `""` |
268270
| `ui.link` | Link to open when the logo is clicked. | `""` |

config/ui/ui.go

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ import (
1010
)
1111

1212
const (
13-
defaultTitle = "Health Dashboard | Gatus"
14-
defaultDescription = "Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue"
15-
defaultHeader = "Gatus"
16-
defaultLogo = ""
17-
defaultLink = ""
18-
defaultCustomCSS = ""
19-
defaultSortBy = "name"
20-
defaultFilterBy = "none"
13+
defaultTitle = "Health Dashboard | Gatus"
14+
defaultDescription = "Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue"
15+
defaultHeader = "Gatus"
16+
defaultDashboardHeading = "Health Dashboard"
17+
defaultDashboardSubheading = "Monitor the health of your endpoints in real-time"
18+
defaultLogo = ""
19+
defaultLink = ""
20+
defaultCustomCSS = ""
21+
defaultSortBy = "name"
22+
defaultFilterBy = "none"
2123
)
2224

2325
var (
@@ -30,17 +32,18 @@ var (
3032

3133
// Config is the configuration for the UI of Gatus
3234
type Config struct {
33-
Title string `yaml:"title,omitempty"` // Title of the page
34-
Description string `yaml:"description,omitempty"` // Meta description of the page
35-
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
36-
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
37-
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
38-
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header
39-
CustomCSS string `yaml:"custom-css,omitempty"` // Custom CSS to include in the page
40-
DarkMode *bool `yaml:"dark-mode,omitempty"` // DarkMode is a flag to enable dark mode by default
41-
DefaultSortBy string `yaml:"default-sort-by,omitempty"` // DefaultSortBy is the default sort option ('name', 'group', 'health')
42-
DefaultFilterBy string `yaml:"default-filter-by,omitempty"` // DefaultFilterBy is the default filter option ('none', 'failing', 'unstable')
43-
35+
Title string `yaml:"title,omitempty"` // Title of the page
36+
Description string `yaml:"description,omitempty"` // Meta description of the page
37+
DashboardHeading string `yaml:"dashboard-heading,omitempty"` // Dashboard Title between header and endpoints
38+
DashboardSubheading string `yaml:"dashboard-subheading,omitempty"` // Dashboard Description between header and endpoints
39+
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
40+
Logo string `yaml:"logo,omitempty"` // Logo to display on the page
41+
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo
42+
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header
43+
CustomCSS string `yaml:"custom-css,omitempty"` // Custom CSS to include in the page
44+
DarkMode *bool `yaml:"dark-mode,omitempty"` // DarkMode is a flag to enable dark mode by default
45+
DefaultSortBy string `yaml:"default-sort-by,omitempty"` // DefaultSortBy is the default sort option ('name', 'group', 'health')
46+
DefaultFilterBy string `yaml:"default-filter-by,omitempty"` // DefaultFilterBy is the default filter option ('none', 'failing', 'unstable')
4447
//////////////////////////////////////////////
4548
// Non-configurable - used for UI rendering //
4649
//////////////////////////////////////////////
@@ -73,6 +76,8 @@ func GetDefaultConfig() *Config {
7376
return &Config{
7477
Title: defaultTitle,
7578
Description: defaultDescription,
79+
DashboardHeading: defaultDashboardHeading,
80+
DashboardSubheading: defaultDashboardSubheading,
7681
Header: defaultHeader,
7782
Logo: defaultLogo,
7883
Link: defaultLink,
@@ -92,6 +97,12 @@ func (cfg *Config) ValidateAndSetDefaults() error {
9297
if len(cfg.Description) == 0 {
9398
cfg.Description = defaultDescription
9499
}
100+
if len(cfg.DashboardHeading) == 0 {
101+
cfg.DashboardHeading = defaultDashboardHeading
102+
}
103+
if len(cfg.DashboardSubheading) == 0 {
104+
cfg.DashboardSubheading = defaultDashboardSubheading
105+
}
95106
if len(cfg.Header) == 0 {
96107
cfg.Header = defaultHeader
97108
}

config/ui/ui_test.go

Lines changed: 110 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,110 @@ import (
77
)
88

99
func TestConfig_ValidateAndSetDefaults(t *testing.T) {
10-
cfg := &Config{
11-
Title: "",
12-
Description: "",
13-
Header: "",
14-
Logo: "",
15-
Link: "",
16-
}
17-
if err := cfg.ValidateAndSetDefaults(); err != nil {
18-
t.Error("expected no error, got", err.Error())
19-
}
20-
if cfg.Title != defaultTitle {
21-
t.Errorf("expected title to be %s, got %s", defaultTitle, cfg.Title)
22-
}
23-
if cfg.Description != defaultDescription {
24-
t.Errorf("expected description to be %s, got %s", defaultDescription, cfg.Description)
25-
}
26-
if cfg.Header != defaultHeader {
27-
t.Errorf("expected header to be %s, got %s", defaultHeader, cfg.Header)
28-
}
29-
if cfg.DefaultSortBy != defaultSortBy {
30-
t.Errorf("expected defaultSortBy to be %s, got %s", defaultSortBy, cfg.DefaultSortBy)
31-
}
32-
if cfg.DefaultFilterBy != defaultFilterBy {
33-
t.Errorf("expected defaultFilterBy to be %s, got %s", defaultFilterBy, cfg.DefaultFilterBy)
34-
}
10+
t.Run("empty-config", func(t *testing.T) {
11+
cfg := &Config{
12+
Title: "",
13+
Description: "",
14+
DashboardHeading: "",
15+
DashboardSubheading: "",
16+
Header: "",
17+
Logo: "",
18+
Link: "",
19+
}
20+
if err := cfg.ValidateAndSetDefaults(); err != nil {
21+
t.Error("expected no error, got", err.Error())
22+
}
23+
if cfg.Title != defaultTitle {
24+
t.Errorf("expected title to be %s, got %s", defaultTitle, cfg.Title)
25+
}
26+
if cfg.Description != defaultDescription {
27+
t.Errorf("expected description to be %s, got %s", defaultDescription, cfg.Description)
28+
}
29+
if cfg.DashboardHeading != defaultDashboardHeading {
30+
t.Errorf("expected DashboardHeading to be %s, got %s", defaultDashboardHeading, cfg.DashboardHeading)
31+
}
32+
if cfg.DashboardSubheading != defaultDashboardSubheading {
33+
t.Errorf("expected DashboardSubheading to be %s, got %s", defaultDashboardSubheading, cfg.DashboardSubheading)
34+
}
35+
if cfg.Header != defaultHeader {
36+
t.Errorf("expected header to be %s, got %s", defaultHeader, cfg.Header)
37+
}
38+
if cfg.DefaultSortBy != defaultSortBy {
39+
t.Errorf("expected defaultSortBy to be %s, got %s", defaultSortBy, cfg.DefaultSortBy)
40+
}
41+
if cfg.DefaultFilterBy != defaultFilterBy {
42+
t.Errorf("expected defaultFilterBy to be %s, got %s", defaultFilterBy, cfg.DefaultFilterBy)
43+
}
44+
})
45+
t.Run("custom-values", func(t *testing.T) {
46+
cfg := &Config{
47+
Title: "Custom Title",
48+
Description: "Custom Description",
49+
DashboardHeading: "Production Status",
50+
DashboardSubheading: "Monitor all production endpoints",
51+
Header: "My Company",
52+
Logo: "https://example.com/logo.png",
53+
Link: "https://example.com",
54+
DefaultSortBy: "health",
55+
DefaultFilterBy: "failing",
56+
}
57+
if err := cfg.ValidateAndSetDefaults(); err != nil {
58+
t.Error("expected no error, got", err.Error())
59+
}
60+
if cfg.Title != "Custom Title" {
61+
t.Errorf("expected title to be preserved, got %s", cfg.Title)
62+
}
63+
if cfg.Description != "Custom Description" {
64+
t.Errorf("expected description to be preserved, got %s", cfg.Description)
65+
}
66+
if cfg.DashboardHeading != "Production Status" {
67+
t.Errorf("expected DashboardHeading to be preserved, got %s", cfg.DashboardHeading)
68+
}
69+
if cfg.DashboardSubheading != "Monitor all production endpoints" {
70+
t.Errorf("expected DashboardSubheading to be preserved, got %s", cfg.DashboardSubheading)
71+
}
72+
if cfg.Header != "My Company" {
73+
t.Errorf("expected header to be preserved, got %s", cfg.Header)
74+
}
75+
if cfg.Logo != "https://example.com/logo.png" {
76+
t.Errorf("expected logo to be preserved, got %s", cfg.Logo)
77+
}
78+
if cfg.Link != "https://example.com" {
79+
t.Errorf("expected link to be preserved, got %s", cfg.Link)
80+
}
81+
if cfg.DefaultSortBy != "health" {
82+
t.Errorf("expected defaultSortBy to be preserved, got %s", cfg.DefaultSortBy)
83+
}
84+
if cfg.DefaultFilterBy != "failing" {
85+
t.Errorf("expected defaultFilterBy to be preserved, got %s", cfg.DefaultFilterBy)
86+
}
87+
})
88+
t.Run("partial-custom-values", func(t *testing.T) {
89+
cfg := &Config{
90+
Title: "Custom Title",
91+
DashboardHeading: "My Dashboard",
92+
Header: "",
93+
DashboardSubheading: "",
94+
}
95+
if err := cfg.ValidateAndSetDefaults(); err != nil {
96+
t.Error("expected no error, got", err.Error())
97+
}
98+
if cfg.Title != "Custom Title" {
99+
t.Errorf("expected custom title to be preserved, got %s", cfg.Title)
100+
}
101+
if cfg.DashboardHeading != "My Dashboard" {
102+
t.Errorf("expected custom DashboardHeading to be preserved, got %s", cfg.DashboardHeading)
103+
}
104+
if cfg.DashboardSubheading != defaultDashboardSubheading {
105+
t.Errorf("expected DashboardSubheading to use default, got %s", cfg.DashboardSubheading)
106+
}
107+
if cfg.Header != defaultHeader {
108+
t.Errorf("expected header to use default, got %s", cfg.Header)
109+
}
110+
if cfg.Description != defaultDescription {
111+
t.Errorf("expected description to use default, got %s", cfg.Description)
112+
}
113+
})
35114
}
36115

37116
func TestButton_Validate(t *testing.T) {
@@ -78,6 +157,12 @@ func TestGetDefaultConfig(t *testing.T) {
78157
if defaultConfig.Title != defaultTitle {
79158
t.Error("expected GetDefaultConfig() to return defaultTitle, got", defaultConfig.Title)
80159
}
160+
if defaultConfig.DashboardHeading != defaultDashboardHeading {
161+
t.Error("expected GetDefaultConfig() to return defaultDashboardHeading, got", defaultConfig.DashboardHeading)
162+
}
163+
if defaultConfig.DashboardSubheading != defaultDashboardSubheading {
164+
t.Error("expected GetDefaultConfig() to return defaultDashboardSubheading, got", defaultConfig.DashboardSubheading)
165+
}
81166
if defaultConfig.Logo != defaultLogo {
82167
t.Error("expected GetDefaultConfig() to return defaultLogo, got", defaultConfig.Logo)
83168
}

web/app/public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="utf-8" />
55
<script type="text/javascript">
6-
window.config = {logo: "{{ .UI.Logo }}", header: "{{ .UI.Header }}", link: "{{ .UI.Link }}", buttons: [], maximumNumberOfResults: "{{ .UI.MaximumNumberOfResults }}", defaultSortBy: "{{ .UI.DefaultSortBy }}", defaultFilterBy: "{{ .UI.DefaultFilterBy }}"};{{- range .UI.Buttons}}window.config.buttons.push({name:"{{ .Name }}",link:"{{ .Link }}"});{{end}}
6+
window.config = {logo: "{{ .UI.Logo }}", header: "{{ .UI.Header }}", dashboardHeading: "{{ .UI.DashboardHeading }}", dashboardSubheading: "{{ .UI.DashboardSubheading }}", link: "{{ .UI.Link }}", buttons: [], maximumNumberOfResults: "{{ .UI.MaximumNumberOfResults }}", defaultSortBy: "{{ .UI.DefaultSortBy }}", defaultFilterBy: "{{ .UI.DefaultFilterBy }}"};{{- range .UI.Buttons}}window.config.buttons.push({name:"{{ .Name }}",link:"{{ .Link }}"});{{end}}
77
// Initialize theme immediately to prevent flash
88
(function() {
99
const themeFromCookie = document.cookie.match(/theme=(dark|light);?/)?.[1];

web/app/src/views/Home.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
<div class="mb-6">
55
<div class="flex items-center justify-between mb-6">
66
<div>
7-
<h1 class="text-4xl font-bold tracking-tight">Health Dashboard</h1>
8-
<p class="text-muted-foreground mt-2">Monitor the health of your endpoints in real-time</p>
7+
<h1 class="text-4xl font-bold tracking-tight">{{ dashboardHeading }}</h1>
8+
<p class="text-muted-foreground mt-2">{{ dashboardSubheading }}</p>
99
</div>
1010
<div class="flex items-center gap-4">
1111
<Button
@@ -532,6 +532,14 @@ const initializeCollapsedGroups = () => {
532532
}
533533
}
534534
535+
const dashboardHeading = computed(() => {
536+
return window.config && window.config.dashboardHeading && window.config.dashboardHeading !== '{{ .UI.DashboardHeading }}' ? window.config.dashboardHeading : "Health Dashboard"
537+
})
538+
539+
const dashboardSubheading = computed(() => {
540+
return window.config && window.config.dashboardSubheading && window.config.dashboardSubheading !== '{{ .UI.dashboardSubheading }}' ? window.config.dashboardSubheading : "Monitor the health of your endpoints in real-time"
541+
})
542+
535543
onMounted(() => {
536544
fetchData()
537545
})

web/static/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!doctype html><html lang="en" class="{{ .Theme }}"><head><meta charset="utf-8"/><script>window.config = {logo: "{{ .UI.Logo }}", header: "{{ .UI.Header }}", link: "{{ .UI.Link }}", buttons: [], maximumNumberOfResults: "{{ .UI.MaximumNumberOfResults }}", defaultSortBy: "{{ .UI.DefaultSortBy }}", defaultFilterBy: "{{ .UI.DefaultFilterBy }}"};{{- range .UI.Buttons}}window.config.buttons.push({name:"{{ .Name }}",link:"{{ .Link }}"});{{end}}
1+
<!doctype html><html lang="en" class="{{ .Theme }}"><head><meta charset="utf-8"/><script>window.config = {logo: "{{ .UI.Logo }}", header: "{{ .UI.Header }}", dashboardHeading: "{{ .UI.DashboardHeading }}", dashboardSubheading: "{{ .UI.DashboardSubheading }}", link: "{{ .UI.Link }}", buttons: [], maximumNumberOfResults: "{{ .UI.MaximumNumberOfResults }}", defaultSortBy: "{{ .UI.DefaultSortBy }}", defaultFilterBy: "{{ .UI.DefaultFilterBy }}"};{{- range .UI.Buttons}}window.config.buttons.push({name:"{{ .Name }}",link:"{{ .Link }}"});{{end}}
22
// Initialize theme immediately to prevent flash
33
(function() {
44
const themeFromCookie = document.cookie.match(/theme=(dark|light);?/)?.[1];

web/static/js/app.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)