浏览代码

feat(preferences): theme and home dashbord settings now work work on profile and org settings page

Torkel Ödegaard 9 年之前
父节点
当前提交
ab1048b7ee

+ 7 - 1
pkg/api/api.go

@@ -96,12 +96,15 @@ func Register(r *macaron.Macaron) {
 			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
 			r.Post("/using/:id", wrap(UserSetUsingOrg))
 			r.Get("/orgs", wrap(GetSignedInUserOrgList))
+
 			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
 			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
+
 			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
 			r.Get("/quotas", wrap(GetUserQuotas))
+
 			r.Get("/preferences", wrap(GetUserPreferences))
-			r.Put("/preferences", bind(dtos.UpdateUserPrefsCmd{}), wrap(UpdateUserPreferences))
+			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
 		})
 
 		// users (admin permission required)
@@ -132,6 +135,9 @@ func Register(r *macaron.Macaron) {
 			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
 			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
 
+			// prefs
+			r.Get("/preferences", wrap(GetOrgPreferences))
+			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
 		}, reqOrgAdmin)
 
 		// create new org

+ 6 - 8
pkg/api/dashboard.go

@@ -159,22 +159,20 @@ func canEditDashboard(role m.RoleType) bool {
 }
 
 func GetHomeDashboard(c *middleware.Context) {
-	// Checking if there is any preference set for home dashboard
-	query := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
-
-	if err := bus.Dispatch(&query); err != nil {
+	prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
+	if err := bus.Dispatch(&prefsQuery); err != nil {
 		c.JsonApiErr(500, "Failed to get preferences", err)
 	}
 
-	if query.Result.HomeDashboardId != 0 {
-		query := m.GetDashboardSlugByIdQuery{Id: query.Result.HomeDashboardId}
-		err := bus.Dispatch(&query)
+	if prefsQuery.Result.HomeDashboardId != 0 {
+		slugQuery := m.GetDashboardSlugByIdQuery{Id: prefsQuery.Result.HomeDashboardId}
+		err := bus.Dispatch(&slugQuery)
 		if err != nil {
 			c.JsonApiErr(500, "Failed to get slug from database", err)
 			return
 		}
 
-		dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + query.Result}
+		dashRedirect := dtos.DashboardRedirect{RedirectUri: "db/" + slugQuery.Result}
 		c.JSON(200, &dashRedirect)
 		return
 	}

+ 1 - 0
pkg/api/dtos/models.go

@@ -33,6 +33,7 @@ type CurrentUser struct {
 	OrgRole        m.RoleType `json:"orgRole"`
 	IsGrafanaAdmin bool       `json:"isGrafanaAdmin"`
 	GravatarUrl    string     `json:"gravatarUrl"`
+	Timezone       string     `json:"timezone"`
 }
 
 type DashboardMeta struct {

+ 5 - 8
pkg/api/dtos/prefs.go

@@ -1,15 +1,12 @@
 package dtos
 
-type UserPrefs struct {
-	Theme                  string `json:"theme"`
-	ThemeDefault           string `json:"themeDefault"`
-	HomeDashboardId        int64  `json:"homeDashboardId"`
-	HomeDashboardIdDefault int64  `json:"homeDashboardIdDefault"`
-	Timezone               string `json:"timezone"`
-	TimezoneDefault        string `json:"timezoneDefault"`
+type Prefs struct {
+	Theme           string `json:"theme"`
+	HomeDashboardId int64  `json:"homeDashboardId"`
+	Timezone        string `json:"timezone"`
 }
 
-type UpdateUserPrefsCmd struct {
+type UpdatePrefsCmd struct {
 	Theme           string `json:"theme"`
 	HomeDashboardId int64  `json:"homeDashboardId"`
 	Timezone        string `json:"timezone"`

+ 9 - 1
pkg/api/index.go

@@ -2,6 +2,7 @@ package api
 
 import (
 	"github.com/grafana/grafana/pkg/api/dtos"
+	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/plugins"
@@ -14,6 +15,12 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 		return nil, err
 	}
 
+	prefsQuery := m.GetPreferencesWithDefaultsQuery{OrgId: c.OrgId, UserId: c.UserId}
+	if err := bus.Dispatch(&prefsQuery); err != nil {
+		return nil, err
+	}
+	prefs := prefsQuery.Result
+
 	var data = dtos.IndexViewData{
 		User: &dtos.CurrentUser{
 			Id:             c.UserId,
@@ -21,12 +28,13 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
 			Login:          c.Login,
 			Email:          c.Email,
 			Name:           c.Name,
-			LightTheme:     c.Theme == "light",
 			OrgId:          c.OrgId,
 			OrgName:        c.OrgName,
 			OrgRole:        c.OrgRole,
 			GravatarUrl:    dtos.GetGravatarUrl(c.Email),
 			IsGrafanaAdmin: c.IsGrafanaAdmin,
+			LightTheme:     prefs.Theme == "light",
+			Timezone:       prefs.Timezone,
 		},
 		Settings:           settings,
 		AppUrl:             setting.AppUrl,

+ 30 - 12
pkg/api/preferences.go

@@ -22,34 +22,52 @@ func SetHomeDashboard(c *middleware.Context, cmd m.SavePreferencesCommand) Respo
 
 // GET /api/user/preferences
 func GetUserPreferences(c *middleware.Context) Response {
-	userPrefs := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
+	return getPreferencesFor(c.OrgId, c.UserId)
+}
+
+func getPreferencesFor(orgId int64, userId int64) Response {
+	prefsQuery := m.GetPreferencesQuery{UserId: userId, OrgId: orgId}
 
-	if err := bus.Dispatch(&userPrefs); err != nil {
-		c.JsonApiErr(500, "Failed to get preferences", err)
+	if err := bus.Dispatch(&prefsQuery); err != nil {
+		return ApiError(500, "Failed to get preferences", err)
 	}
 
-	dto := dtos.UserPrefs{
-		Theme:           userPrefs.Result.Theme,
-		HomeDashboardId: userPrefs.Result.HomeDashboardId,
-		Timezone:        userPrefs.Result.Timezone,
+	dto := dtos.Prefs{
+		Theme:           prefsQuery.Result.Theme,
+		HomeDashboardId: prefsQuery.Result.HomeDashboardId,
+		Timezone:        prefsQuery.Result.Timezone,
 	}
 
 	return Json(200, &dto)
 }
 
 // PUT /api/user/preferences
-func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdateUserPrefsCmd) Response {
+func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
+	return updatePreferencesFor(c.OrgId, c.UserId, &dtoCmd)
+}
+
+func updatePreferencesFor(orgId int64, userId int64, dtoCmd *dtos.UpdatePrefsCmd) Response {
 	saveCmd := m.SavePreferencesCommand{
-		UserId:          c.UserId,
-		OrgId:           c.OrgId,
+		UserId:          userId,
+		OrgId:           orgId,
 		Theme:           dtoCmd.Theme,
 		Timezone:        dtoCmd.Timezone,
 		HomeDashboardId: dtoCmd.HomeDashboardId,
 	}
 
 	if err := bus.Dispatch(&saveCmd); err != nil {
-		c.JsonApiErr(500, "Failed to save preferences", err)
+		return ApiError(500, "Failed to save preferences", err)
 	}
 
-	return ApiSuccess("User preferences updated")
+	return ApiSuccess("Preferences updated")
+}
+
+// GET /api/org/preferences
+func GetOrgPreferences(c *middleware.Context) Response {
+	return getPreferencesFor(c.OrgId, 0)
+}
+
+// PUT /api/org/preferences
+func UpdateOrgPreferences(c *middleware.Context, dtoCmd dtos.UpdatePrefsCmd) Response {
+	return updatePreferencesFor(c.OrgId, 0, &dtoCmd)
 }

+ 8 - 0
pkg/models/preferences.go

@@ -33,6 +33,14 @@ type GetPreferencesQuery struct {
 	Result *Preferences
 }
 
+type GetPreferencesWithDefaultsQuery struct {
+	Id     int64
+	OrgId  int64
+	UserId int64
+
+	Result *Preferences
+}
+
 // ---------------------
 // COMMANDS
 type SavePreferencesCommand struct {

+ 0 - 1
pkg/models/user.go

@@ -136,7 +136,6 @@ type SignedInUser struct {
 	Login          string
 	Name           string
 	Email          string
-	Theme          string
 	ApiKeyId       int64
 	IsGrafanaAdmin bool
 }

+ 36 - 1
pkg/services/sqlstore/preferences.go

@@ -9,9 +9,44 @@ import (
 
 func init() {
 	bus.AddHandler("sql", GetPreferences)
+	bus.AddHandler("sql", GetPreferencesWithDefaults)
 	bus.AddHandler("sql", SavePreferences)
 }
 
+func GetPreferencesWithDefaults(query *m.GetPreferencesWithDefaultsQuery) error {
+
+	prefs := make([]*m.Preferences, 0)
+	filter := "(org_id=? AND user_id=?) OR (org_id=? AND user_id=0)"
+	err := x.Where(filter, query.OrgId, query.UserId, query.OrgId).
+		OrderBy("user_id ASC").
+		Find(&prefs)
+
+	if err != nil {
+		return err
+	}
+
+	res := &m.Preferences{
+		Theme:           "dark",
+		Timezone:        "browser",
+		HomeDashboardId: 0,
+	}
+
+	for _, p := range prefs {
+		if p.Theme != "" {
+			res.Theme = p.Theme
+		}
+		if p.Timezone != "" {
+			res.Timezone = p.Timezone
+		}
+		if p.HomeDashboardId != 0 {
+			res.HomeDashboardId = p.HomeDashboardId
+		}
+	}
+
+	query.Result = res
+	return nil
+}
+
 func GetPreferences(query *m.GetPreferencesQuery) error {
 
 	var prefs m.Preferences
@@ -54,7 +89,7 @@ func SavePreferences(cmd *m.SavePreferencesCommand) error {
 			prefs.Theme = cmd.Theme
 			prefs.Updated = time.Now()
 			prefs.Version += 1
-			_, err = sess.Id(prefs.Id).Update(&prefs)
+			_, err := sess.Id(prefs.Id).AllCols().Update(&prefs)
 			return err
 		}
 	})

+ 0 - 1
pkg/services/sqlstore/user.go

@@ -273,7 +273,6 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
 	                u.email        as email,
 	                u.login        as login,
 									u.name         as name,
-									u.theme        as theme,
 	                org.name       as org_name,
 	                org_user.role  as org_role,
 	                org.id         as org_id

+ 6 - 3
public/app/core/routes/routes.ts

@@ -88,17 +88,20 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
     resolve: loadOrgBundle,
   })
   .when('/profile', {
-    templateUrl: 'public/app/features/profile/partials/profile.html',
+    templateUrl: 'public/app/features/org/partials/profile.html',
     controller : 'ProfileCtrl',
     controllerAs: 'ctrl',
+    resolve: loadOrgBundle,
   })
   .when('/profile/password', {
-    templateUrl: 'public/app/features/profile/partials/password.html',
+    templateUrl: 'public/app/features/org/partials/password.html',
     controller : 'ChangePasswordCtrl',
+    resolve: loadOrgBundle,
   })
   .when('/profile/select-org', {
-    templateUrl: 'public/app/features/profile/partials/select_org.html',
+    templateUrl: 'public/app/features/org/partials/select_org.html',
     controller : 'SelectOrgCtrl',
+    resolve: loadOrgBundle,
   })
   // ADMIN
   .when('/admin', {

+ 0 - 3
public/app/features/all.js

@@ -7,8 +7,5 @@ define([
   './playlist/all',
   './snapshot/all',
   './panel/all',
-  './profile/profile_ctrl',
-  './profile/changePasswordCtrl',
-  './profile/selectOrgCtrl',
   './styleguide/styleguide',
 ], function () {});

+ 4 - 0
public/app/features/org/all.js

@@ -1,7 +1,11 @@
 define([
   './org_users_ctrl',
+  './profile_ctrl',
+  './org_users_ctrl',
+  './select_org_ctrl',
   './newOrgCtrl',
   './userInviteCtrl',
   './orgApiKeysCtrl',
   './orgDetailsCtrl',
+  './prefs_control',
 ], function () {});

+ 0 - 0
public/app/features/profile/changePasswordCtrl.js → public/app/features/org/change_password_ctrl.js


+ 0 - 0
public/app/features/profile/partials/password.html → public/app/features/org/partials/change_password.html


+ 2 - 0
public/app/features/org/partials/orgDetails.html

@@ -19,6 +19,8 @@
 		</div>
 	</form>
 
+	<prefs-control mode="org"></prefs-control>
+
 	<h3 class="page-heading">Address</h3>
 
 	<form name="addressForm" class="gf-form-group">

+ 1 - 30
public/app/features/profile/partials/profile.html → public/app/features/org/partials/profile.html

@@ -26,36 +26,7 @@
 		</div>
 	</form>
 
-	<form name="ctrl.prefsForm" class="gf-form-group">
-		<h3 class="page-heading">Preferences</h3>
-
-		<div class="gf-form">
-			<span class="gf-form-label width-9">UI Theme</span>
-			<div class="gf-form-select-wrapper max-width-20">
-				<select class="gf-form-input" ng-model="ctrl.prefs.theme" ng-options="f.value as f.text for f in ctrl.themes"></select>
-			</div>
-		</div>
-
-		<div class="gf-form">
-			<span class="gf-form-label width-9">Home Dashboard</span>
-			<dashboard-selector
-         class="gf-form-select-wrapper max-width-20"
-         model="ctrl.prefs.homeDashboardId">
-      </dashboard-selector>
-		</div>
-
-		<div class="gf-form">
-			<label class="gf-form-label width-9">Timezone</label>
-			<div class="gf-form-select-wrapper max-width-20">
-				<select class="gf-form-input" ng-model="ctrl.prefs.timezone" ng-options="f.value as f.text for f in ctrl.timezones"></select>
-			</div>
-		</div>
-
-		<div class="gf-form-button-row">
-			<button type="submit" class="btn btn-success" ng-click="ctrl.updatePrefs()">Update</button>
-		</div>
-	</form>
-
+	<prefs-control mode="user"></prefs-control>
 
 	<h3 class="page-heading">Password</h3>
 	<div class="gf-form-group">

+ 0 - 0
public/app/features/profile/partials/select_org.html → public/app/features/org/partials/select_org.html


+ 100 - 0
public/app/features/org/prefs_control.ts

@@ -0,0 +1,100 @@
+///<reference path="../../headers/common.d.ts" />
+
+import config from 'app/core/config';
+import _ from 'lodash';
+import coreModule from '../../core/core_module';
+
+export class PrefsControlCtrl {
+  prefs: any;
+  oldTheme: any;
+  prefsForm: any;
+  mode: string;
+
+  timezones: any = [
+    {value: '', text: 'Default'},
+    {value: 'browser', text: 'Local browser time'},
+    {value: 'utc', text: 'UTC'},
+  ];
+  themes: any = [
+    {value: '', text: 'Default'},
+    {value: 'dark', text: 'Dark'},
+    {value: 'light', text: 'Light'},
+  ];
+
+  /** @ngInject **/
+  constructor(private backendSrv, private $location) {
+  }
+
+  $onInit() {
+    return this.backendSrv.get(`/api/${this.mode}/preferences`).then(prefs => {
+      this.prefs = prefs;
+      this.oldTheme = prefs.theme;
+    });
+  }
+
+  updatePrefs() {
+    if (!this.prefsForm.$valid) { return; }
+
+    var cmd = {
+      theme: this.prefs.theme,
+      timezone: this.prefs.timezone,
+      homeDashboardId: this.prefs.homeDashboardId
+    };
+
+    this.backendSrv.put(`/api/${this.mode}/preferences`, cmd).then(() => {
+      if (this.oldTheme !== cmd.theme) {
+        window.location.href = config.appSubUrl + this.$location.path();
+      }
+    });
+  }
+
+}
+
+var template = `
+<form name="ctrl.prefsForm" class="gf-form-group">
+  <h3 class="page-heading">Preferences</h3>
+
+  <div class="gf-form">
+    <span class="gf-form-label width-9">UI Theme</span>
+    <div class="gf-form-select-wrapper max-width-20">
+      <select class="gf-form-input" ng-model="ctrl.prefs.theme" ng-options="f.value as f.text for f in ctrl.themes"></select>
+    </div>
+  </div>
+
+  <div class="gf-form">
+    <span class="gf-form-label width-9">Home Dashboard</span>
+    <dashboard-selector
+        class="gf-form-select-wrapper max-width-20"
+        model="ctrl.prefs.homeDashboardId">
+    </dashboard-selector>
+  </div>
+
+  <div class="gf-form">
+    <label class="gf-form-label width-9">Timezone</label>
+    <div class="gf-form-select-wrapper max-width-20">
+      <select class="gf-form-input" ng-model="ctrl.prefs.timezone" ng-options="f.value as f.text for f in ctrl.timezones"></select>
+    </div>
+  </div>
+
+  <div class="gf-form-button-row">
+    <button type="submit" class="btn btn-success" ng-click="ctrl.updatePrefs()">Update</button>
+  </div>
+</form>
+`;
+
+export function prefsControlDirective() {
+  return {
+    restrict: 'E',
+    controller: PrefsControlCtrl,
+    bindToController: true,
+    controllerAs: 'ctrl',
+    template: template,
+    scope: {
+      mode: "@"
+    }
+  };
+}
+
+coreModule.directive('prefsControl', prefsControlDirective);
+
+

+ 1 - 37
public/app/features/profile/profile_ctrl.ts → public/app/features/org/profile_ctrl.ts

@@ -8,26 +8,12 @@ export class ProfileCtrl {
   user: any;
   old_theme: any;
   orgs: any;
-  prefs: any;
   userForm: any;
-  prefsForm: any;
-
-  timezones: any = [
-    {value: '', text: 'Default'},
-    {value: 'browser', text: 'Local browser time'},
-    {value: 'utc', text: 'UTC'},
-  ];
-  themes: any = [
-    {value: '', text: 'Default'},
-    {value: 'dark', text: 'Dark'},
-    {value: 'light', text: 'Light'},
-  ];
 
   /** @ngInject **/
-  constructor(private $scope, private backendSrv, private contextSrv, private $location) {
+  constructor(private backendSrv, private contextSrv, private $location) {
     this.getUser();
     this.getUserOrgs();
-    this.getUserPrefs();
   }
 
   getUser() {
@@ -37,13 +23,6 @@ export class ProfileCtrl {
     });
   }
 
-  getUserPrefs() {
-    this.backendSrv.get('/api/user/preferences').then(prefs => {
-      this.prefs = prefs;
-      this.old_theme = prefs.theme;
-    });
-  }
-
   getUserOrgs() {
     this.backendSrv.get('/api/user/orgs').then(orgs => {
       this.orgs = orgs;
@@ -67,21 +46,6 @@ export class ProfileCtrl {
     });
   }
 
-  updatePrefs() {
-    if (!this.prefsForm.$valid) { return; }
-
-    var cmd = {
-      theme: this.prefs.theme,
-      timezone: this.prefs.timezone,
-      homeDashboardId: this.prefs.homeDashboardId
-    };
-
-    this.backendSrv.put('/api/user/preferences', cmd).then(() => {
-      if (this.old_theme !== cmd.theme) {
-        window.location.href = config.appSubUrl + this.$location.path();
-      }
-    });
-  }
 }
 
 coreModule.controller('ProfileCtrl', ProfileCtrl);

+ 0 - 0
public/app/features/profile/selectOrgCtrl.js → public/app/features/org/select_org_ctrl.js