Commit 39eba506 by Wouter Smeenk Committed by GitHub

Dashboard: Support configuring default timezone via config file (#27404)

Add a default timezone that the administrator can set in the settings. 
This setting is be used as default for the users timezone preference.
Can be used when creating Grafana instances without administrator 
intervention, in order to give user the correct default timezone.

Fixes #25654
parent 53153c82
......@@ -823,4 +823,5 @@ interval_year = YYYY
# Experimental feature
use_browser_locale = false
# Default timezone for user preferences. Options are 'browser' for the browser local timezone or a timezone name from IANA Time Zone database, e.g. 'UTC' or 'Europe/Amsterdam' etc.
default_timezone = browser
......@@ -811,3 +811,6 @@
# Experimental feature
;use_browser_locale = false
# Default timezone for user preferences. Options are 'browser' for the browser local timezone or a timezone name from IANA Time Zone database, e.g. 'UTC' or 'Europe/Amsterdam' etc.
;default_timezone = browser
\ No newline at end of file
......@@ -1426,3 +1426,6 @@ interval_year = YYYY
Set this to `true` to have date formats be automatically be derived from browser locale. Defaults to `false`. This
is an experimental feature right now with a few problems that remain unsolved.
### default_timezone
Used as the default timezone for user preferences. Can be either `browser` for the browser local timezone or a timezone name from IANA Time Zone database, e.g. `UTC` or `Europe/Amsterdam` etc.
\ No newline at end of file
......@@ -32,7 +32,7 @@ Your Grafana preferences include whether uses the dark or light theme, your home
1. In the Preferences section, you can edit any of the following:
- **UI Theme -** Click to set the **Dark** or **Light** to select a theme. **Default** is either the dark theme or the theme selected by your Grafana administrator.
- **Home Dashboard -** Refer to [Set your personal home dashboard]({{< relref "change-home-dashboard.md#set-your-personal-home-dashboard" >}}) for more information.
- **Timezone -** Click to select an option in the **Timezone** list. Refer to [Time range controls]({{< relref "../dashboards/time-range-controls.md" >}}) for more information about Grafana time settings.
- **Timezone -** Click to select an option in the **Timezone** list. **Default** is either the browser local timezone or the timezone selected by your Grafana administrator. Refer to [Time range controls]({{< relref "../dashboards/time-range-controls.md" >}}) for more information about Grafana time settings.
1. Click **Save**.
## View your assigned organizations
......
......@@ -10,13 +10,13 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
func init() {
func (ss *SqlStore) addPreferencesQueryAndCommandHandlers() {
bus.AddHandler("sql", GetPreferences)
bus.AddHandler("sql", GetPreferencesWithDefaults)
bus.AddHandler("sql", ss.GetPreferencesWithDefaults)
bus.AddHandler("sql", SavePreferences)
}
func GetPreferencesWithDefaults(query *models.GetPreferencesWithDefaultsQuery) error {
func (ss *SqlStore) GetPreferencesWithDefaults(query *models.GetPreferencesWithDefaultsQuery) error {
params := make([]interface{}, 0)
filter := ""
......@@ -43,7 +43,7 @@ func GetPreferencesWithDefaults(query *models.GetPreferencesWithDefaultsQuery) e
res := &models.Preferences{
Theme: setting.DefaultTheme,
Timezone: "browser",
Timezone: ss.Cfg.DateFormats.DefaultTimezone,
HomeDashboardId: 0,
}
......
......@@ -11,14 +11,17 @@ import (
func TestPreferencesDataAccess(t *testing.T) {
Convey("Testing preferences data access", t, func() {
InitTestDB(t)
ss := InitTestDB(t)
Convey("GetPreferencesWithDefaults with no saved preferences should return defaults", func() {
setting.DefaultTheme = "light"
ss.Cfg.DateFormats.DefaultTimezone = "UTC"
query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{}}
err := GetPreferencesWithDefaults(query)
err := ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.Theme, ShouldEqual, setting.DefaultTheme)
So(query.Result.Timezone, ShouldEqual, "browser")
So(query.Result.Theme, ShouldEqual, "light")
So(query.Result.Timezone, ShouldEqual, "UTC")
So(query.Result.HomeDashboardId, ShouldEqual, 0)
})
......@@ -29,7 +32,7 @@ func TestPreferencesDataAccess(t *testing.T) {
So(err, ShouldBeNil)
query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 1}}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 4)
})
......@@ -41,7 +44,7 @@ func TestPreferencesDataAccess(t *testing.T) {
So(err, ShouldBeNil)
query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1, UserId: 2}}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 1)
})
......@@ -57,7 +60,7 @@ func TestPreferencesDataAccess(t *testing.T) {
query := &models.GetPreferencesWithDefaultsQuery{
User: &models.SignedInUser{OrgId: 1, Teams: []int64{2, 3}},
}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 3)
})
......@@ -71,7 +74,7 @@ func TestPreferencesDataAccess(t *testing.T) {
So(err, ShouldBeNil)
query := &models.GetPreferencesWithDefaultsQuery{User: &models.SignedInUser{OrgId: 1}}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 1)
})
......@@ -89,7 +92,7 @@ func TestPreferencesDataAccess(t *testing.T) {
query := &models.GetPreferencesWithDefaultsQuery{
User: &models.SignedInUser{OrgId: 1, UserId: 1, Teams: []int64{2, 3}},
}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 4)
})
......@@ -107,7 +110,7 @@ func TestPreferencesDataAccess(t *testing.T) {
query := &models.GetPreferencesWithDefaultsQuery{
User: &models.SignedInUser{OrgId: 1, UserId: 2},
}
err = GetPreferencesWithDefaults(query)
err = ss.GetPreferencesWithDefaults(query)
So(err, ShouldBeNil)
So(query.Result.HomeDashboardId, ShouldEqual, 1)
})
......
......@@ -102,6 +102,7 @@ func (ss *SqlStore) Init() error {
// Register handlers
ss.addUserQueryAndCommandHandlers()
ss.addAlertNotificationUidByIdHandler()
ss.addPreferencesQueryAndCommandHandlers()
err = ss.logOrgsNotice()
if err != nil {
......
package setting
import (
"time"
"gopkg.in/ini.v1"
)
type DateFormats struct {
FullDate string `json:"fullDate"`
UseBrowserLocale bool `json:"useBrowserLocale"`
Interval DateFormatIntervals `json:"interval"`
DefaultTimezone string `json:"defaultTimezone"`
}
type DateFormatIntervals struct {
......@@ -15,6 +22,23 @@ type DateFormatIntervals struct {
Year string `json:"year"`
}
const LocalBrowserTimezone = "browser"
func valueAsTimezone(section *ini.Section, keyName string, defaultValue string) (string, error) {
timezone := section.Key(keyName).MustString(defaultValue)
if timezone == LocalBrowserTimezone {
return LocalBrowserTimezone, nil
}
location, err := time.LoadLocation(timezone)
if err != nil {
return LocalBrowserTimezone, err
}
return location.String(), nil
}
func (cfg *Cfg) readDateFormats() {
dateFormats := cfg.Raw.Section("date_formats")
cfg.DateFormats.FullDate = valueAsString(dateFormats, "full_date", "YYYY-MM-DD HH:mm:ss")
......@@ -25,4 +49,10 @@ func (cfg *Cfg) readDateFormats() {
cfg.DateFormats.Interval.Month = valueAsString(dateFormats, "interval_month", "YYYY-MM")
cfg.DateFormats.Interval.Year = "YYYY"
cfg.DateFormats.UseBrowserLocale = dateFormats.Key("date_format_use_browser_locale").MustBool(false)
timezone, err := valueAsTimezone(dateFormats, "default_timezone", LocalBrowserTimezone)
if err != nil {
cfg.Logger.Warn("Unknown timezone as default_timezone", "err", err)
}
cfg.DateFormats.DefaultTimezone = timezone
}
package setting
import (
"testing"
"gopkg.in/ini.v1"
"github.com/stretchr/testify/assert"
)
func TestValueAsTimezone(t *testing.T) {
tests := map[string]struct {
output string
hasErr bool
}{
"browser": {"browser", false},
"UTC": {"UTC", false},
"utc": {"browser", true},
"Amsterdam": {"browser", true},
"europe/amsterdam": {"browser", true},
"Europe/Amsterdam": {"Europe/Amsterdam", false},
}
sec, err := ini.Empty().NewSection("test")
assert.NoError(t, err)
key, err := sec.NewKey("test", "")
assert.NoError(t, err)
for input, expected := range tests {
key.SetValue(input)
output, err := valueAsTimezone(sec, "test", "default")
assert.Equal(t, expected.hasErr, err != nil, "Invalid has err for input: %s err: %v", input, err)
assert.Equal(t, expected.output, output, "Invalid output for input: %s", input)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment