mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
feat(backend): allow configuring defaults for the UI
This commit is contained in:
@@ -79,10 +79,17 @@ func index(c *gin.Context) {
|
||||
}
|
||||
filtersB64 := base64.StdEncoding.EncodeToString(filtersJSON)
|
||||
|
||||
defaults, err := json.Marshal(config.Config.UI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defaultsB64 := base64.StdEncoding.EncodeToString(defaults)
|
||||
|
||||
c.HTML(http.StatusOK, "ui/build/index.html", gin.H{
|
||||
"Version": version,
|
||||
"SentryDSN": config.Config.Sentry.Public,
|
||||
"DefaultFilter": filtersB64,
|
||||
"Defaults": defaultsB64,
|
||||
})
|
||||
|
||||
log.Infof("[%s] %s %s took %s", c.ClientIP(), c.Request.Method, c.Request.RequestURI, time.Since(start))
|
||||
|
||||
@@ -615,7 +615,7 @@ sentry:
|
||||
|
||||
## Silence form
|
||||
|
||||
`silenceForm` section allow customizing silence form behavior.
|
||||
`silenceForm` section allows customizing silence form behavior.
|
||||
`author:populate_from_header` subsection allows to configure fetching of author
|
||||
name used on the silence form from the request header. It can be used with
|
||||
setups where karma is deployed behind authentication proxy that adds some extra
|
||||
@@ -660,6 +660,52 @@ silenceForm:
|
||||
- job
|
||||
```
|
||||
|
||||
## UI defaults
|
||||
|
||||
`ui` section allows configuring default values for UI settings controled via the
|
||||
configuration modal. Those defaults can be overwritten by use via UI controls.
|
||||
|
||||
Syntax:
|
||||
|
||||
```YAML
|
||||
ui:
|
||||
refresh: duration
|
||||
hideFiltersWhenIdle: bool
|
||||
colorTitlebar: bool
|
||||
minimalGroupWidth: integer
|
||||
alertsPerGroup: integer
|
||||
collapseGroups: string
|
||||
```
|
||||
|
||||
- `refresh` - default refresh interval, this tells the UI how often karma API
|
||||
should be queried
|
||||
- `hideFiltersWhenIdle` - if enabled filter bar will be hidden after some
|
||||
user inactivity
|
||||
- `colorTitlebar` - if enabled alert group title bar color will be set to follow
|
||||
alerts in that group
|
||||
- `minimalGroupWidth` - minimal width (in pixels) for each alert group rendered
|
||||
on the grid. This value is used to calculate the number of columns rendered on
|
||||
the grid.
|
||||
- `alertsPerGroup` - default number of alerts to show for each group
|
||||
- `collapseGroups` - controls if alert groups will default to being rendered
|
||||
expanded or collapsed (only title bar is visible). Valid values:
|
||||
- expanded - groups are always expanded
|
||||
- collapsed - groups are always collapsed
|
||||
- collapsedOnMobile - groups are expanded on desktop and collapsed on mobile
|
||||
browsers
|
||||
|
||||
Defaults:
|
||||
|
||||
```YAML
|
||||
ui:
|
||||
refresh: 30s
|
||||
hideFiltersWhenIdle: true
|
||||
colorTitlebar: false
|
||||
minimalGroupWidth: 420
|
||||
alertsPerGroup: 5
|
||||
collapseGroups: collapsedOnMobile
|
||||
```
|
||||
|
||||
## Customizing karma
|
||||
|
||||
In order to keep the core code simple karma doesn't support any way of extending
|
||||
|
||||
@@ -57,3 +57,10 @@ silenceForm:
|
||||
strip:
|
||||
labels:
|
||||
- job
|
||||
ui:
|
||||
refresh: 30s
|
||||
hideFiltersWhenIdle: true
|
||||
colorTitlebar: false
|
||||
minimalGroupWidth: 420
|
||||
alertsPerGroup: 5
|
||||
collapseGroups: collapsedOnMobile
|
||||
|
||||
@@ -90,6 +90,13 @@ func init() {
|
||||
|
||||
pflag.String("sentry.public", "", "Sentry DSN for Go exceptions")
|
||||
pflag.String("sentry.private", "", "Sentry DSN for JavaScript exceptions")
|
||||
|
||||
pflag.Duration("ui.refresh", time.Second*30, "UI refresh interval")
|
||||
pflag.Bool("ui.hideFiltersWhenIdle", true, "Hide the filters bar when idle")
|
||||
pflag.Bool("ui.colorTitlebar", false, "Color alert group titlebar based on alert state")
|
||||
pflag.Int("ui.minimalGroupWidth", 420, "Minimal width for each alert group on the grid")
|
||||
pflag.Int("ui.alertsPerGroup", 5, "Default number of alerts to show for each alert group")
|
||||
pflag.String("ui.collapseGroups", "collapsedOnMobile", "Default state for alert groups")
|
||||
}
|
||||
|
||||
// ReadConfig will read all sources of configuration, merge all keys and
|
||||
@@ -173,6 +180,12 @@ func (config *configSchema) Read() {
|
||||
config.SilenceForm.Strip.Labels = v.GetStringSlice("silenceform.strip.labels")
|
||||
config.SilenceForm.Author.PopulateFromHeader.Header = v.GetString("silenceform.author.populate_from_header.header")
|
||||
config.SilenceForm.Author.PopulateFromHeader.ValueRegex = v.GetString("silenceform.author.populate_from_header.value_re")
|
||||
config.UI.Refresh = v.GetDuration("ui.refresh")
|
||||
config.UI.HideFiltersWhenIdle = v.GetBool("ui.hideFiltersWhenIdle")
|
||||
config.UI.ColorTitlebar = v.GetBool("ui.colorTitlebar")
|
||||
config.UI.MinimalGroupWidth = v.GetInt("ui.minimalGroupWidth")
|
||||
config.UI.AlertsPerGroup = v.GetInt("ui.alertsPerGroup")
|
||||
config.UI.CollapseGroups = v.GetString("ui.collapseGroups")
|
||||
|
||||
if config.SilenceForm.Author.PopulateFromHeader.ValueRegex != "" {
|
||||
_, err = regexp.Compile(config.SilenceForm.Author.PopulateFromHeader.ValueRegex)
|
||||
@@ -223,6 +236,10 @@ func (config *configSchema) Read() {
|
||||
log.Fatalf("Invalid grid.sorting.order value '%s', allowed options: disabled, startsAt, label", config.Grid.Sorting.Order)
|
||||
}
|
||||
|
||||
if !slices.StringInSlice([]string{"expanded", "collapsed", "collapsedOnMobile"}, config.UI.CollapseGroups) {
|
||||
log.Fatalf("Invalid ui.collapseGroups value '%s', allowed options: expanded, collapsed, collapsedOnMobile", config.UI.CollapseGroups)
|
||||
}
|
||||
|
||||
// FIXME workaround for https://github.com/prymitive/karma/issues/507
|
||||
// until https://github.com/spf13/viper/pull/635 is merged
|
||||
// read in raw config file if it's used and override maps where keys are label
|
||||
|
||||
@@ -129,6 +129,13 @@ silenceForm:
|
||||
value_re: ""
|
||||
strip:
|
||||
labels: []
|
||||
ui:
|
||||
refresh: 30s
|
||||
hideFiltersWhenIdle: true
|
||||
colorTitlebar: false
|
||||
minimalGroupWidth: 420
|
||||
alertsPerGroup: 5
|
||||
collapseGroups: collapsedOnMobile
|
||||
`
|
||||
|
||||
configDump, err := yaml.Marshal(Config)
|
||||
@@ -259,3 +266,35 @@ func TestInvalidSilenceFormRegex(t *testing.T) {
|
||||
t.Error("Invalid silence form regex didn't cause log.Fatal()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidGridSortingOrder(t *testing.T) {
|
||||
resetEnv()
|
||||
os.Setenv("GRID_SORTING_ORDER", "foo")
|
||||
|
||||
log.SetLevel(log.PanicLevel)
|
||||
defer func() { log.StandardLogger().ExitFunc = nil }()
|
||||
var wasFatal bool
|
||||
log.StandardLogger().ExitFunc = func(int) { wasFatal = true }
|
||||
|
||||
Config.Read()
|
||||
|
||||
if !wasFatal {
|
||||
t.Error("Invalid grid.sorting.order value didn't cause log.Fatal()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidUICollapseGroups(t *testing.T) {
|
||||
resetEnv()
|
||||
os.Setenv("UI_COLLAPSEGROUPS", "foo")
|
||||
|
||||
log.SetLevel(log.PanicLevel)
|
||||
defer func() { log.StandardLogger().ExitFunc = nil }()
|
||||
var wasFatal bool
|
||||
log.StandardLogger().ExitFunc = func(int) { wasFatal = true }
|
||||
|
||||
Config.Read()
|
||||
|
||||
if !wasFatal {
|
||||
t.Error("Invalid ui.collapseGroups value didn't cause log.Fatal()")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,4 +105,12 @@ type configSchema struct {
|
||||
Labels []string
|
||||
}
|
||||
} `yaml:"silenceForm" mapstructure:"silenceForm"`
|
||||
UI struct {
|
||||
Refresh time.Duration
|
||||
HideFiltersWhenIdle bool `yaml:"hideFiltersWhenIdle" mapstructure:"hideFiltersWhenIdle"`
|
||||
ColorTitlebar bool `yaml:"colorTitlebar" mapstructure:"colorTitlebar"`
|
||||
MinimalGroupWidth int `yaml:"minimalGroupWidth" mapstructure:"minimalGroupWidth"`
|
||||
AlertsPerGroup int `yaml:"alertsPerGroup" mapstructure:"alertsPerGroup"`
|
||||
CollapseGroups string `yaml:"collapseGroups" mapstructure:"collapseGroups"`
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user