feat(ui): Allow configuring meta description (#342)

* feat: add description prop to HTML template

* feat: add desc property to backend config validation

* test: add desc field to ui config test

* chore: add default description text

* test: add test for description default

* docs: add description config option explanation

* Update README.md

* Update config/ui/ui_test.go

Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
David Wheatley 2022-11-01 05:33:19 +01:00 committed by GitHub
parent fe4d9821f3
commit 22d74a5ea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 76 additions and 66 deletions

View File

@ -157,54 +157,54 @@ If you want to test it locally, see [Docker](#docker).
## Configuration ## Configuration
| Parameter | Description | Default | | Parameter | Description | Default |
|:------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------| | :---------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------- |
| `debug` | Whether to enable debug logs. | `false` | | `debug` | Whether to enable debug logs. | `false` |
| `metrics` | Whether to expose metrics at /metrics. | `false` | | `metrics` | Whether to expose metrics at /metrics. | `false` |
| `storage` | [Storage configuration](#storage) | `{}` | | `storage` | [Storage configuration](#storage) | `{}` |
| `endpoints` | List of endpoints to monitor. | Required `[]` | | `endpoints` | List of endpoints to monitor. | Required `[]` |
| `endpoints[].enabled` | Whether to monitor the endpoint. | `true` | | `endpoints[].enabled` | Whether to monitor the endpoint. | `true` |
| `endpoints[].name` | Name of the endpoint. Can be anything. | Required `""` | | `endpoints[].name` | Name of the endpoint. Can be anything. | Required `""` |
| `endpoints[].group` | Group name. Used to group multiple endpoints together on the dashboard. <br />See [Endpoint groups](#endpoint-groups). | `""` | | `endpoints[].group` | Group name. Used to group multiple endpoints together on the dashboard. <br />See [Endpoint groups](#endpoint-groups). | `""` |
| `endpoints[].url` | URL to send the request to. | Required `""` | | `endpoints[].url` | URL to send the request to. | Required `""` |
| `endpoints[].method` | Request method. | `GET` | | `endpoints[].method` | Request method. | `GET` |
| `endpoints[].conditions` | Conditions used to determine the health of the endpoint. <br />See [Conditions](#conditions). | `[]` | | `endpoints[].conditions` | Conditions used to determine the health of the endpoint. <br />See [Conditions](#conditions). | `[]` |
| `endpoints[].interval` | Duration to wait between every status check. | `60s` | | `endpoints[].interval` | Duration to wait between every status check. | `60s` |
| `endpoints[].graphql` | Whether to wrap the body in a query param (`{"query":"$body"}`). | `false` | | `endpoints[].graphql` | Whether to wrap the body in a query param (`{"query":"$body"}`). | `false` |
| `endpoints[].body` | Request body. | `""` | | `endpoints[].body` | Request body. | `""` |
| `endpoints[].headers` | Request headers. | `{}` | | `endpoints[].headers` | Request headers. | `{}` |
| `endpoints[].dns` | Configuration for an endpoint of type DNS. <br />See [Monitoring an endpoint using DNS queries](#monitoring-an-endpoint-using-dns-queries). | `""` | | `endpoints[].dns` | Configuration for an endpoint of type DNS. <br />See [Monitoring an endpoint using DNS queries](#monitoring-an-endpoint-using-dns-queries). | `""` |
| `endpoints[].dns.query-type` | Query type (e.g. MX) | `""` | | `endpoints[].dns.query-type` | Query type (e.g. MX) | `""` |
| `endpoints[].dns.query-name` | Query name (e.g. example.com) | `""` | | `endpoints[].dns.query-name` | Query name (e.g. example.com) | `""` |
| `endpoints[].alerts[].type` | Type of alert. <br />Valid types: `slack`, `discord`, `email`, `googlechat`, `pagerduty`, `twilio`, `mattermost`, `messagebird`, `teams` `custom`. | Required `""` | | `endpoints[].alerts[].type` | Type of alert. <br />Valid types: `slack`, `discord`, `email`, `googlechat`, `pagerduty`, `twilio`, `mattermost`, `messagebird`, `teams` `custom`. | Required `""` |
| `endpoints[].alerts[].enabled` | Whether to enable the alert. | `false` | | `endpoints[].alerts[].enabled` | Whether to enable the alert. | `false` |
| `endpoints[].alerts[].failure-threshold` | Number of failures in a row needed before triggering the alert. | `3` | | `endpoints[].alerts[].failure-threshold` | Number of failures in a row needed before triggering the alert. | `3` |
| `endpoints[].alerts[].success-threshold` | Number of successes in a row before an ongoing incident is marked as resolved. | `2` | | `endpoints[].alerts[].success-threshold` | Number of successes in a row before an ongoing incident is marked as resolved. | `2` |
| `endpoints[].alerts[].send-on-resolved` | Whether to send a notification once a triggered alert is marked as resolved. | `false` | | `endpoints[].alerts[].send-on-resolved` | Whether to send a notification once a triggered alert is marked as resolved. | `false` |
| `endpoints[].alerts[].description` | Description of the alert. Will be included in the alert sent. | `""` | | `endpoints[].alerts[].description` | Description of the alert. Will be included in the alert sent. | `""` |
| `endpoints[].client` | [Client configuration](#client-configuration). | `{}` | | `endpoints[].client` | [Client configuration](#client-configuration). | `{}` |
| `endpoints[].ui` | UI configuration at the endpoint level. | `{}` | | `endpoints[].ui` | UI configuration at the endpoint level. | `{}` |
| `endpoints[].ui.hide-hostname` | Whether to hide the hostname in the result. | `false` | | `endpoints[].ui.hide-hostname` | Whether to hide the hostname in the result. | `false` |
| `endpoints[].ui.hide-url` | Whether to ensure the URL is not displayed in the results. Useful if the URL contains a token. | `false` | | `endpoints[].ui.hide-url` | Whether to ensure the URL is not displayed in the results. Useful if the URL contains a token. | `false` |
| `endpoints[].ui.dont-resolve-failed-conditions` | Whether to resolve failed conditions for the UI. | `false` | | `endpoints[].ui.dont-resolve-failed-conditions` | Whether to resolve failed conditions for the UI. | `false` |
| `endpoints[].ui.badge.reponse-time` | List of response time thresholds. Each time a threshold is reached, the badge has a different color. | `[50, 200, 300, 500, 750]` | | `endpoints[].ui.badge.reponse-time` | List of response time thresholds. Each time a threshold is reached, the badge has a different color. | `[50, 200, 300, 500, 750]` |
| `alerting` | [Alerting configuration](#alerting). | `{}` | | `alerting` | [Alerting configuration](#alerting). | `{}` |
| `security` | [Security configuration](#security). | `{}` | | `security` | [Security configuration](#security). | `{}` |
| `disable-monitoring-lock` | Whether to [disable the monitoring lock](#disable-monitoring-lock). | `false` | | `disable-monitoring-lock` | Whether to [disable the monitoring lock](#disable-monitoring-lock). | `false` |
| `skip-invalid-config-update` | Whether to ignore invalid configuration update. <br />See [Reloading configuration on the fly](#reloading-configuration-on-the-fly). | `false` | | `skip-invalid-config-update` | Whether to ignore invalid configuration update. <br />See [Reloading configuration on the fly](#reloading-configuration-on-the-fly). | `false` |
| `web` | Web configuration. | `{}` | | `web` | Web configuration. | `{}` |
| `web.address` | Address to listen on. | `0.0.0.0` | | `web.address` | Address to listen on. | `0.0.0.0` |
| `web.port` | Port to listen on. | `8080` | | `web.port` | Port to listen on. | `8080` |
| `ui` | UI configuration. | `{}` | | `ui` | UI configuration. | `{}` |
| `ui.title` | [Title of the document](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title). | `Health Dashboard ǀ Gatus` | | `ui.title` | [Title of the document](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title). | `Health Dashboard ǀ Gatus` |
| `ui.header` | Header at the top of the dashboard. | `Health Status` | | `ui.description` | Meta description for the page. | `Gatus is an advanced...`. |
| `ui.logo` | URL to the logo to display. | `""` | | `ui.header` | Header at the top of the dashboard. | `Health Status` |
| `ui.link` | Link to open when the logo is clicked. | `""` | | `ui.logo` | URL to the logo to display. | `""` |
| `ui.buttons` | List of buttons to display below the header. | `[]` | | `ui.link` | Link to open when the logo is clicked. | `""` |
| `ui.buttons[].name` | Text to display on the button. | Required `""` | | `ui.buttons` | List of buttons to display below the header. | `[]` |
| `ui.buttons[].link` | Link to open when the button is clicked. | Required `""` | | `ui.buttons[].name` | Text to display on the button. | Required `""` |
| `maintenance` | [Maintenance configuration](#maintenance). | `{}` | | `ui.buttons[].link` | Link to open when the button is clicked. | Required `""` |
| `maintenance` | [Maintenance configuration](#maintenance). | `{}` |
### Conditions ### Conditions
Here are some examples of conditions you can use: Here are some examples of conditions you can use:

View File

@ -9,10 +9,11 @@ import (
) )
const ( const (
defaultTitle = "Health Dashboard | Gatus" defaultTitle = "Health Dashboard | Gatus"
defaultHeader = "Health Status" 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"
defaultLogo = "" defaultHeader = "Health Status"
defaultLink = "" defaultLogo = ""
defaultLink = ""
) )
var ( var (
@ -21,11 +22,12 @@ var (
// Config is the configuration for the UI of Gatus // Config is the configuration for the UI of Gatus
type Config struct { type Config struct {
Title string `yaml:"title,omitempty"` // Title of the page Title string `yaml:"title,omitempty"` // Title of the page
Header string `yaml:"header,omitempty"` // Header is the text at the top of the page Description string `yaml:"description,omitempty"` // Meta description of the page
Logo string `yaml:"logo,omitempty"` // Logo to display on the page Header string `yaml:"header,omitempty"` // Header is the text at the top of the page
Link string `yaml:"link,omitempty"` // Link to open when clicking on the logo Logo string `yaml:"logo,omitempty"` // Logo to display on the page
Buttons []Button `yaml:"buttons,omitempty"` // Buttons to display below the header 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 // Button is the configuration for a button on the UI
@ -45,10 +47,11 @@ func (btn *Button) Validate() error {
// GetDefaultConfig returns a Config struct with the default values // GetDefaultConfig returns a Config struct with the default values
func GetDefaultConfig() *Config { func GetDefaultConfig() *Config {
return &Config{ return &Config{
Title: defaultTitle, Title: defaultTitle,
Header: defaultHeader, Description: defaultDescription,
Logo: defaultLogo, Header: defaultHeader,
Link: defaultLink, Logo: defaultLogo,
Link: defaultLink,
} }
} }
@ -57,6 +60,9 @@ func (cfg *Config) ValidateAndSetDefaults() error {
if len(cfg.Title) == 0 { if len(cfg.Title) == 0 {
cfg.Title = defaultTitle cfg.Title = defaultTitle
} }
if len(cfg.Description) == 0 {
cfg.Description = defaultDescription
}
if len(cfg.Header) == 0 { if len(cfg.Header) == 0 {
cfg.Header = defaultHeader cfg.Header = defaultHeader
} }

View File

@ -7,10 +7,11 @@ import (
func TestConfig_ValidateAndSetDefaults(t *testing.T) { func TestConfig_ValidateAndSetDefaults(t *testing.T) {
cfg := &Config{ cfg := &Config{
Title: "", Title: "",
Header: "", Description: "",
Logo: "", Header: "",
Link: "", Logo: "",
Link: "",
} }
if err := cfg.ValidateAndSetDefaults(); err != nil { if err := cfg.ValidateAndSetDefaults(); err != nil {
t.Error("expected no error, got", err.Error()) t.Error("expected no error, got", err.Error())
@ -18,6 +19,9 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
if cfg.Title != defaultTitle { if cfg.Title != defaultTitle {
t.Errorf("expected title to be %s, got %s", defaultTitle, cfg.Title) t.Errorf("expected title to be %s, got %s", defaultTitle, cfg.Title)
} }
if cfg.Description != defaultDescription {
t.Errorf("expected description to be %s, got %s", defaultDescription, cfg.Description)
}
if cfg.Header != defaultHeader { if cfg.Header != defaultHeader {
t.Errorf("expected header to be %s, got %s", defaultHeader, cfg.Header) t.Errorf("expected header to be %s, got %s", defaultHeader, cfg.Header)
} }

View File

@ -11,7 +11,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="shortcut icon" href="/favicon.ico" /> <link rel="shortcut icon" href="/favicon.ico" />
<meta property="description" content="Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue" /> <meta property="description" content="{{ .Description }}" />
</head> </head>
<body class="dark:bg-gray-900"> <body class="dark:bg-gray-900">
<noscript><strong>Enable JavaScript to view this page.</strong></noscript> <noscript><strong>Enable JavaScript to view this page.</strong></noscript>