mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
progress
This commit is contained in:
parent
f165ba6480
commit
38a10f8be4
@ -100,6 +100,8 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
|
r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
|
||||||
r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
|
r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
|
||||||
r.Get("/quotas", wrap(GetUserQuotas))
|
r.Get("/quotas", wrap(GetUserQuotas))
|
||||||
|
r.Get("/preferences", wrap(GetUserPreferences))
|
||||||
|
r.Put("/preferences", bind(dtos.UpdateUserPrefsCmd{}), wrap(UpdateUserPreferences))
|
||||||
})
|
})
|
||||||
|
|
||||||
// users (admin permission required)
|
// users (admin permission required)
|
||||||
|
@ -159,7 +159,6 @@ func canEditDashboard(role m.RoleType) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetHomeDashboard(c *middleware.Context) {
|
func GetHomeDashboard(c *middleware.Context) {
|
||||||
|
|
||||||
// Checking if there is any preference set for home dashboard
|
// Checking if there is any preference set for home dashboard
|
||||||
query := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
|
query := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
package dtos
|
package dtos
|
||||||
|
|
||||||
type Preferences struct {
|
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 UpdateUserPrefsCmd struct {
|
||||||
Theme string `json:"theme"`
|
Theme string `json:"theme"`
|
||||||
HomeDashboardId int64 `json:"homeDashboardId"`
|
HomeDashboardId int64 `json:"homeDashboardId"`
|
||||||
Timezone string `json:"timezone"`
|
Timezone string `json:"timezone"`
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
@ -18,3 +19,37 @@ func SetHomeDashboard(c *middleware.Context, cmd m.SavePreferencesCommand) Respo
|
|||||||
|
|
||||||
return ApiSuccess("Home dashboard set")
|
return ApiSuccess("Home dashboard set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET /api/user/preferences
|
||||||
|
func GetUserPreferences(c *middleware.Context) Response {
|
||||||
|
userPrefs := m.GetPreferencesQuery{UserId: c.UserId, OrgId: c.OrgId}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&userPrefs); err != nil {
|
||||||
|
c.JsonApiErr(500, "Failed to get preferences", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := dtos.UserPrefs{
|
||||||
|
Theme: userPrefs.Result.Theme,
|
||||||
|
HomeDashboardId: userPrefs.Result.HomeDashboardId,
|
||||||
|
Timezone: userPrefs.Result.Timezone,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(200, &dto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /api/user/preferences
|
||||||
|
func UpdateUserPreferences(c *middleware.Context, dtoCmd dtos.UpdateUserPrefsCmd) Response {
|
||||||
|
saveCmd := m.SavePreferencesCommand{
|
||||||
|
UserId: c.UserId,
|
||||||
|
OrgId: c.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 ApiSuccess("User preferences updated")
|
||||||
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package sqlstore
|
package sqlstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -6,12 +6,25 @@ import $ from 'jquery';
|
|||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
|
|
||||||
var template = `
|
var template = `
|
||||||
|
<select class="gf-form-input" ng-model="ctrl.model" ng-options="f.value as f.text for f in ctrl.options"></select>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export class DashboardSelectorCtrl {
|
export class DashboardSelectorCtrl {
|
||||||
|
model: any;
|
||||||
|
options: any;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $scope, private $rootScope) {
|
constructor(private backendSrv) {
|
||||||
|
}
|
||||||
|
|
||||||
|
$onInit() {
|
||||||
|
this.options = [{value: 0, text: 'Default'}];
|
||||||
|
|
||||||
|
return this.backendSrv.search({starred: true}).then(res => {
|
||||||
|
res.forEach(dash => {
|
||||||
|
this.options.push({value: dash.id, text: dash.title});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +35,9 @@ export function dashboardSelector() {
|
|||||||
bindToController: true,
|
bindToController: true,
|
||||||
controllerAs: 'ctrl',
|
controllerAs: 'ctrl',
|
||||||
template: template,
|
template: template,
|
||||||
|
scope: {
|
||||||
|
model: '='
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import {liveSrv} from './live/live_srv';
|
|||||||
import {Emitter} from './utils/emitter';
|
import {Emitter} from './utils/emitter';
|
||||||
import {layoutSelector} from './components/layout_selector/layout_selector';
|
import {layoutSelector} from './components/layout_selector/layout_selector';
|
||||||
import {switchDirective} from './components/switch';
|
import {switchDirective} from './components/switch';
|
||||||
|
import {dashboardSelector} from './components/dashboard_selector';
|
||||||
import 'app/core/controllers/all';
|
import 'app/core/controllers/all';
|
||||||
import 'app/core/services/all';
|
import 'app/core/services/all';
|
||||||
import 'app/core/routes/routes';
|
import 'app/core/routes/routes';
|
||||||
@ -54,4 +55,5 @@ export {
|
|||||||
infoPopover,
|
infoPopover,
|
||||||
Emitter,
|
Emitter,
|
||||||
appEvents,
|
appEvents,
|
||||||
|
dashboardSelector,
|
||||||
};
|
};
|
||||||
|
@ -90,6 +90,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
|
|||||||
.when('/profile', {
|
.when('/profile', {
|
||||||
templateUrl: 'public/app/features/profile/partials/profile.html',
|
templateUrl: 'public/app/features/profile/partials/profile.html',
|
||||||
controller : 'ProfileCtrl',
|
controller : 'ProfileCtrl',
|
||||||
|
controllerAs: 'ctrl',
|
||||||
})
|
})
|
||||||
.when('/profile/password', {
|
.when('/profile/password', {
|
||||||
templateUrl: 'public/app/features/profile/partials/password.html',
|
templateUrl: 'public/app/features/profile/partials/password.html',
|
||||||
|
@ -7,7 +7,7 @@ define([
|
|||||||
'./playlist/all',
|
'./playlist/all',
|
||||||
'./snapshot/all',
|
'./snapshot/all',
|
||||||
'./panel/all',
|
'./panel/all',
|
||||||
'./profile/profileCtrl',
|
'./profile/profile_ctrl',
|
||||||
'./profile/changePasswordCtrl',
|
'./profile/changePasswordCtrl',
|
||||||
'./profile/selectOrgCtrl',
|
'./profile/selectOrgCtrl',
|
||||||
'./styleguide/styleguide',
|
'./styleguide/styleguide',
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
<h3 class="page-heading">Address</h3>
|
<h3 class="page-heading">Address</h3>
|
||||||
|
|
||||||
<form name="addressForm" class="gf-form-group">
|
<form name="addressForm" class="gf-form-group">
|
||||||
|
@ -6,35 +6,57 @@
|
|||||||
<h1>Profile</h1>
|
<h1>Profile</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form name="userForm" class="gf-form-group">
|
<form name="ctrl.userForm" class="gf-form-group">
|
||||||
<h3 class="page-heading">Preferences</h3>
|
<h3 class="page-heading">Information</h3>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">Name</span>
|
<span class="gf-form-label width-9">Name</span>
|
||||||
<input class="gf-form-input max-width-21" type="text" required ng-model="user.name" >
|
<input class="gf-form-input max-width-21" type="text" required ng-model="ctrl.user.name" >
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">Email</span>
|
<span class="gf-form-label width-9">Email</span>
|
||||||
<input class="gf-form-input max-width-21" type="email" required ng-model="user.email">
|
<input class="gf-form-input max-width-21" type="email" required ng-model="ctrl.user.email">
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">Username</span>
|
<span class="gf-form-label width-9">Username</span>
|
||||||
<input class="gf-form-input max-width-21" type="text" required ng-model="user.login">
|
<input class="gf-form-input max-width-21" type="text" required ng-model="ctrl.user.login">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="gf-form-button-row">
|
||||||
|
<button type="submit" class="btn btn-success" ng-click="ctrl.update()">Update</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form name="ctrl.prefsForm" class="gf-form-group">
|
||||||
|
<h3 class="page-heading">Preferences</h3>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">UI Theme</span>
|
<span class="gf-form-label width-9">UI Theme</span>
|
||||||
<select class="gf-form-input gf-size-auto" ng-model="user.theme" ng-options="f for f in ['dark', 'light']"></select>
|
<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>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">Home Dashboard</span>
|
<span class="gf-form-label width-9">Home Dashboard</span>
|
||||||
<dashboard-selector model="user.homeDashboardId"></dashboard-selector>
|
<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>
|
||||||
|
|
||||||
<div class="gf-form-button-row">
|
<div class="gf-form-button-row">
|
||||||
<button type="submit" class="btn btn-success" ng-click="update()">Update</button>
|
<button type="submit" class="btn btn-success" ng-click="ctrl.updatePrefs()">Update</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
<h3 class="page-heading">Password</h3>
|
<h3 class="page-heading">Password</h3>
|
||||||
<div class="gf-form-group">
|
<div class="gf-form-group">
|
||||||
<a href="profile/password" class="btn btn-inverse">Change Password</a>
|
<a href="profile/password" class="btn btn-inverse">Change Password</a>
|
||||||
@ -51,7 +73,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="org in orgs">
|
<tr ng-repeat="org in ctrl.orgs">
|
||||||
<td>{{org.name}}</td>
|
<td>{{org.name}}</td>
|
||||||
<td>{{org.role}}</td>
|
<td>{{org.role}}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
define([
|
|
||||||
'angular',
|
|
||||||
'app/core/config',
|
|
||||||
],
|
|
||||||
function (angular, config) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
|
||||||
|
|
||||||
module.controller('ProfileCtrl', function($scope, backendSrv, contextSrv, $location) {
|
|
||||||
|
|
||||||
$scope.init = function() {
|
|
||||||
$scope.getUser();
|
|
||||||
$scope.getUserOrgs();
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.getUser = function() {
|
|
||||||
backendSrv.get('/api/user').then(function(user) {
|
|
||||||
$scope.user = user;
|
|
||||||
$scope.user.theme = user.theme || 'dark';
|
|
||||||
$scope.old_theme = $scope.user.theme;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.getUserOrgs = function() {
|
|
||||||
backendSrv.get('/api/user/orgs').then(function(orgs) {
|
|
||||||
$scope.orgs = orgs;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.setUsingOrg = function(org) {
|
|
||||||
backendSrv.post('/api/user/using/' + org.orgId).then(function() {
|
|
||||||
window.location.href = config.appSubUrl + '/profile';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.update = function() {
|
|
||||||
if (!$scope.userForm.$valid) { return; }
|
|
||||||
|
|
||||||
backendSrv.put('/api/user/', $scope.user).then(function() {
|
|
||||||
contextSrv.user.name = $scope.user.name || $scope.user.login;
|
|
||||||
if ($scope.old_theme !== $scope.user.theme) {
|
|
||||||
window.location.href = config.appSubUrl + $location.path();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.init();
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
87
public/app/features/profile/profile_ctrl.ts
Normal file
87
public/app/features/profile/profile_ctrl.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
///<reference path="../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
import config from 'app/core/config';
|
||||||
|
import {coreModule} from 'app/core/core';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
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) {
|
||||||
|
this.getUser();
|
||||||
|
this.getUserOrgs();
|
||||||
|
this.getUserPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser() {
|
||||||
|
this.backendSrv.get('/api/user').then(user => {
|
||||||
|
this.user = user;
|
||||||
|
this.user.theme = user.theme || 'dark';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setUsingOrg(org) {
|
||||||
|
this.backendSrv.post('/api/user/using/' + org.orgId).then(() => {
|
||||||
|
window.location.href = config.appSubUrl + '/profile';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (!this.userForm.$valid) { return; }
|
||||||
|
|
||||||
|
this.backendSrv.put('/api/user/', this.user).then(() => {
|
||||||
|
this.contextSrv.user.name = this.user.name || this.user.login;
|
||||||
|
if (this.old_theme !== this.user.theme) {
|
||||||
|
window.location.href = config.appSubUrl + this.$location.path();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
2
public/vendor/angular/angular.js
vendored
2
public/vendor/angular/angular.js
vendored
@ -30711,4 +30711,4 @@ $provide.value("$locale", {
|
|||||||
|
|
||||||
})(window, document);
|
})(window, document);
|
||||||
|
|
||||||
!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
|
!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
|
||||||
|
Loading…
Reference in New Issue
Block a user