Commit 88bb7f31b0f8b78a335c541df2ed6f4bc71c0065

Authored by Igor Kulikov
1 parent 207642e8

UI: Ability to set default dashboard for customer user

... ... @@ -22,8 +22,9 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin,
22 22 .name;
23 23
24 24 /*@ngInject*/
25   -function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
  25 +function UserService($http, $q, $rootScope, store, jwtHelper, $translate, $state) {
26 26 var currentUser = null,
  27 + currentUserDetails = null,
27 28 userLoaded = false;
28 29
29 30 var refreshTokenQueue = [];
... ... @@ -47,6 +48,8 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
47 48 refreshJwtToken: refreshJwtToken,
48 49 refreshTokenPending: refreshTokenPending,
49 50 updateAuthorizationHeader: updateAuthorizationHeader,
  51 + gotoDefaultPlace: gotoDefaultPlace,
  52 + forceDefaultPlace: forceDefaultPlace,
50 53 logout: logout
51 54 }
52 55
... ... @@ -86,6 +89,7 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
86 89
87 90 function setUserFromJwtToken(jwtToken, refreshToken, notify, doLogout) {
88 91 currentUser = null;
  92 + currentUserDetails = null;
89 93 if (!jwtToken) {
90 94 clearTokenData();
91 95 if (notify) {
... ... @@ -222,7 +226,25 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
222 226 } else if (currentUser) {
223 227 currentUser.authority = "ANONYMOUS";
224 228 }
225   - deferred.resolve();
  229 + if (currentUser.userId) {
  230 + getUser(currentUser.userId).then(
  231 + function success(user) {
  232 + currentUserDetails = user;
  233 + if (currentUserDetails.additionalInfo &&
  234 + currentUserDetails.additionalInfo.defaultDashboardFullscreen) {
  235 + $rootScope.forceFullscreen = currentUserDetails.additionalInfo.defaultDashboardFullscreen === true;
  236 + } else {
  237 + $rootScope.forceFullscreen = false;
  238 + }
  239 + deferred.resolve();
  240 + },
  241 + function fail() {
  242 + deferred.reject();
  243 + }
  244 + )
  245 + } else {
  246 + deferred.reject();
  247 + }
226 248 }, function fail() {
227 249 deferred.reject();
228 250 });
... ... @@ -331,4 +353,40 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
331 353 return deferred.promise;
332 354 }
333 355
  356 + function forceDefaultPlace(to, params) {
  357 + if (currentUser && isAuthenticated()) {
  358 + if (currentUser.authority === 'CUSTOMER_USER') {
  359 + if (currentUserDetails &&
  360 + currentUserDetails.additionalInfo &&
  361 + currentUserDetails.additionalInfo.defaultDashboardId) {
  362 + if ($rootScope.forceFullscreen) {
  363 + if (to.name === 'home.profile') {
  364 + return false;
  365 + } else if (to.name !== 'home.dashboards.dashboard' && params.dashboardId !== currentUserDetails.additionalInfo.defaultDashboardId) {
  366 + return true;
  367 + }
  368 + }
  369 + }
  370 + }
  371 + }
  372 + return false;
  373 + }
  374 +
  375 + function gotoDefaultPlace(params) {
  376 + if (currentUser && isAuthenticated()) {
  377 + var place = 'home.links';
  378 + if (currentUser.authority === 'CUSTOMER_USER') {
  379 + if (currentUserDetails &&
  380 + currentUserDetails.additionalInfo &&
  381 + currentUserDetails.additionalInfo.defaultDashboardId) {
  382 + place = 'home.dashboards.dashboard';
  383 + params = {dashboardId: currentUserDetails.additionalInfo.defaultDashboardId};
  384 + }
  385 + }
  386 + $state.go(place, params);
  387 + } else {
  388 + $state.go('login', params);
  389 + }
  390 + }
  391 +
334 392 }
... ...
... ... @@ -38,7 +38,7 @@ export default function AppConfig($provide,
38 38
39 39 injectTapEventPlugin();
40 40 $locationProvider.html5Mode(true);
41   - $urlRouterProvider.otherwise('/home');
  41 + //$urlRouterProvider.otherwise('/home');
42 42 storeProvider.setCaching(false);
43 43
44 44 $translateProvider.useSanitizeValueStrategy('sanitize');
... ...
... ... @@ -36,6 +36,8 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
36 36
37 37 initWatchers();
38 38
  39 + checkCurrentState();
  40 +
39 41 function initWatchers() {
40 42 $rootScope.unauthenticatedHandle = $rootScope.$on('unauthenticated', function (event, doLogout) {
41 43 if (doLogout) {
... ... @@ -56,22 +58,27 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
56 58 $rootScope.stateChangeStartHandle = $rootScope.$on('$stateChangeStart', function (evt, to, params) {
57 59 if (userService.isUserLoaded() === true) {
58 60 if (userService.isAuthenticated()) {
59   - var authority = userService.getAuthority();
60   - if (to.module === 'public') {
61   - evt.preventDefault();
62   - $state.go('home', params);
63   - } else if (angular.isDefined(to.auth) &&
64   - to.auth.indexOf(authority) === -1) {
  61 + if (userService.forceDefaultPlace(to, params)) {
65 62 evt.preventDefault();
66   - showForbiddenDialog();
67   - } else if (to.redirectTo) {
68   - evt.preventDefault();
69   - $state.go(to.redirectTo, params)
  63 + gotoDefaultPlace(params);
  64 + } else {
  65 + var authority = userService.getAuthority();
  66 + if (to.module === 'public') {
  67 + evt.preventDefault();
  68 + gotoDefaultPlace(params);
  69 + } else if (angular.isDefined(to.auth) &&
  70 + to.auth.indexOf(authority) === -1) {
  71 + evt.preventDefault();
  72 + showForbiddenDialog();
  73 + } else if (to.redirectTo) {
  74 + evt.preventDefault();
  75 + $state.go(to.redirectTo, params)
  76 + }
70 77 }
71 78 } else {
72 79 if (to.module === 'private') {
73 80 evt.preventDefault();
74   - if (to.url === '/home') {
  81 + if (to.url === '/home' || to.url === '/') {
75 82 $state.go('login', params);
76 83 } else {
77 84 showUnauthorizedDialog();
... ... @@ -80,6 +87,9 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
80 87 }
81 88 } else {
82 89 evt.preventDefault();
  90 + if ($rootScope.userLoadedHandle) {
  91 + $rootScope.userLoadedHandle();
  92 + }
83 93 $rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () {
84 94 $rootScope.userLoadedHandle();
85 95 $state.go(to.name, params);
... ... @@ -102,23 +112,26 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
102 112
103 113 function checkCurrentState() {
104 114 if (userService.isUserLoaded() === true) {
105   - var module = $state.$current.module;
106 115 if (userService.isAuthenticated()) {
107   - if ($state.$current.module === 'public') {
108   - $state.go('home');
109   - }
  116 + gotoDefaultPlace();
110 117 } else {
111   - if (angular.isUndefined(module) || !module) {
112   - //$state.go('login');
113   - } else if ($state.$current.module === 'private') {
114   - showUnauthorizedDialog();
115   - }
  118 + $state.go('login');
116 119 }
117 120 } else {
118   - showUnauthorizedDialog();
  121 + if ($rootScope.userLoadedHandle) {
  122 + $rootScope.userLoadedHandle();
  123 + }
  124 + $rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () {
  125 + $rootScope.userLoadedHandle();
  126 + checkCurrentState();
  127 + });
119 128 }
120 129 }
121 130
  131 + function gotoDefaultPlace(params) {
  132 + userService.gotoDefaultPlace(params);
  133 + }
  134 +
122 135 function showUnauthorizedDialog() {
123 136 if (unauthorizedDialog === null) {
124 137 $translate(['access.unauthorized-access',
... ...
... ... @@ -40,27 +40,19 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
40 40 scope.dashboard = null;
41 41 scope.dashboardSearchText = '';
42 42
43   - scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
44   - if (angular.isDefined(scope.dashboardsScope)) {
45   - if (scope.dashboardsScope === 'customer') {
46   - scope.dashboardFetchFunction = dashboardService.getCustomerDashboards;
47   - } else {
48   - scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
49   - }
50   - } else {
51   - if (userService.getAuthority() === 'TENANT_ADMIN') {
52   - scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
53   - } else if (userService.getAuthority() === 'CUSTOMER_USER') {
54   - scope.dashboardFetchFunction = dashboardService.getCustomerDashboards;
55   - }
56   - }
57   -
58 43 scope.fetchDashboards = function(searchText) {
59 44 var pageLink = {limit: 10, textSearch: searchText};
60 45
61 46 var deferred = $q.defer();
62 47
63   - scope.dashboardFetchFunction(pageLink).then(function success(result) {
  48 + var promise;
  49 + if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') {
  50 + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink);
  51 + } else {
  52 + promise = dashboardService.getTenantDashboards(pageLink);
  53 + }
  54 +
  55 + promise.then(function success(result) {
64 56 deferred.resolve(result.data);
65 57 }, function fail() {
66 58 deferred.reject();
... ... @@ -79,6 +71,8 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
79 71 ngModelCtrl.$render = function () {
80 72 if (ngModelCtrl.$viewValue) {
81 73 scope.dashboard = ngModelCtrl.$viewValue;
  74 + } else {
  75 + scope.dashboard = null;
82 76 }
83 77 }
84 78
... ... @@ -106,6 +100,7 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
106 100 link: linker,
107 101 scope: {
108 102 dashboardsScope: '@',
  103 + customerId: '=',
109 104 theForm: '=?',
110 105 tbRequired: '=?',
111 106 selectFirstDashboard: '='
... ...
... ... @@ -108,10 +108,10 @@ section.tb-dashboard-toolbar {
108 108 }
109 109 }
110 110 .md-fab-toolbar-wrapper {
111   - height: 40px;
  111 + height: 50px;
112 112 md-toolbar {
113   - min-height: 36px;
114   - height: 36px;
  113 + min-height: 46px;
  114 + height: 46px;
115 115 md-fab-actions {
116 116 font-size: 16px;
117 117 margin-top: 0px;
... ... @@ -126,7 +126,7 @@ section.tb-dashboard-toolbar {
126 126
127 127 .tb-dashboard-container {
128 128 &.tb-dashboard-toolbar-opened {
129   - margin-top: 40px;
  129 + margin-top: 50px;
130 130 @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
131 131 }
132 132 &.tb-dashboard-toolbar-closed {
... ...
... ... @@ -15,8 +15,8 @@
15 15 limitations under the License.
16 16
17 17 -->
18   -<md-content flex tb-expand-fullscreen="vm.widgetEditMode || vm.iframeMode" expand-button-id="dashboard-expand-button"
19   - hide-expand-button="vm.widgetEditMode || vm.iframeMode" expand-tooltip-direction="bottom"
  18 +<md-content flex tb-expand-fullscreen="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-button-id="dashboard-expand-button"
  19 + hide-expand-button="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-tooltip-direction="bottom"
20 20 ng-style="{'background-color': vm.dashboard.configuration.gridSettings.backgroundColor,
21 21 'background-image': 'url('+vm.dashboard.configuration.gridSettings.backgroundImageUrl+')',
22 22 'background-repeat': 'no-repeat',
... ... @@ -47,6 +47,8 @@
47 47 aria-label="{{ 'fullscreen.fullscreen' | translate }}"
48 48 class="md-icon-button">
49 49 </md-button>
  50 + <tb-user-menu ng-show="forceFullscreen" display-user-info="true">
  51 + </tb-user-menu>
50 52 <tb-timewindow direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow">
51 53 </tb-timewindow>
52 54 <tb-aliases-device-select ng-show="!vm.isEdit"
... ...
... ... @@ -26,9 +26,7 @@ import logoSvg from '../../svg/logo_title_white.svg';
26 26
27 27 /*@ngInject*/
28 28 export default function HomeController(loginService, userService, deviceService, Fullscreen, $scope, $element, $rootScope, $document, $state,
29   - $log, $mdMedia, $animate, $timeout, $translate) {
30   -
31   - var dashboardUser = userService.getCurrentUser();
  29 + $log, $mdMedia, $animate, $timeout) {
32 30
33 31 var siteSideNav = $('.tb-site-sidenav', $element);
34 32
... ... @@ -48,15 +46,11 @@ export default function HomeController(loginService, userService, deviceService,
48 46 vm.isShowSidenav = false;
49 47 vm.isLockSidenav = false;
50 48
51   - vm.authorityName = authorityName;
52 49 vm.displaySearchMode = displaySearchMode;
53   - vm.logout = logout;
54   - vm.openProfile = openProfile;
55 50 vm.openSidenav = openSidenav;
56 51 vm.searchTextUpdated = searchTextUpdated;
57 52 vm.sidenavClicked = sidenavClicked;
58 53 vm.toggleFullscreen = toggleFullscreen;
59   - vm.userDisplayName = userDisplayName;
60 54
61 55 $scope.$on('$stateChangeSuccess', function (evt, to, toParams, from) {
62 56 if (angular.isDefined(to.data.searchEnabled)) {
... ... @@ -106,50 +100,6 @@ export default function HomeController(loginService, userService, deviceService,
106 100 $scope.$broadcast('searchTextUpdated');
107 101 }
108 102
109   - function authorityName() {
110   - var name = "user.anonymous";
111   - if (dashboardUser) {
112   - var authority = dashboardUser.authority;
113   - if (authority === 'SYS_ADMIN') {
114   - name = 'user.sys-admin';
115   - } else if (authority === 'TENANT_ADMIN') {
116   - name = 'user.tenant-admin';
117   - } else if (authority === 'CUSTOMER_USER') {
118   - name = 'user.customer';
119   - }
120   - }
121   - return $translate.instant(name);
122   - }
123   -
124   - function userDisplayName() {
125   - var name = "";
126   - if (dashboardUser) {
127   - if ((dashboardUser.firstName && dashboardUser.firstName.length > 0) ||
128   - (dashboardUser.lastName && dashboardUser.lastName.length > 0)) {
129   - if (dashboardUser.firstName) {
130   - name += dashboardUser.firstName;
131   - }
132   - if (dashboardUser.lastName) {
133   - if (name.length > 0) {
134   - name += " ";
135   - }
136   - name += dashboardUser.lastName;
137   - }
138   - } else {
139   - name = dashboardUser.email;
140   - }
141   - }
142   - return name;
143   - }
144   -
145   - function openProfile() {
146   - $state.go('home.profile');
147   - }
148   -
149   - function logout() {
150   - userService.logout();
151   - }
152   -
153 103 function openSidenav() {
154 104 vm.isShowSidenav = true;
155 105 }
... ...
... ... @@ -53,37 +53,11 @@ md-sidenav.tb-site-sidenav {
53 53 width: 250px;
54 54 }
55 55
56   -md-icon.tb-mini-avatar {
57   - margin: auto 8px;
58   - font-size: 36px;
59   - height: 36px;
60   - width: 36px;
61   -}
62   -
63 56 md-icon.tb-logo-title {
64 57 height: 36px;
65 58 width: 200px;
66 59 }
67 60
68   -div.tb-user-info {
69   - line-height: 1.5;
70   - span {
71   - text-transform: none;
72   - text-align: left;
73   - }
74   - span.tb-user-display-name {
75   - font-size: 0.800rem;
76   - font-weight: 300;
77   - letter-spacing: 0.008em;
78   - }
79   - span.tb-user-authority {
80   - font-size: 0.800rem;
81   - font-weight: 300;
82   - letter-spacing: 0.005em;
83   - opacity: 0.8;
84   - }
85   -}
86   -
87 61 .tb-nav-header {
88 62 flex-shrink: 0;
89 63 z-index: 2;
... ...
... ... @@ -16,6 +16,7 @@
16 16
17 17 -->
18 18 <md-sidenav class="tb-site-sidenav md-sidenav-left md-whiteframe-z2"
  19 + ng-show="!forceFullscreen"
19 20 hide-print=""
20 21 md-component-id="left"
21 22 aria-label="Toggle Nav"
... ... @@ -59,33 +60,10 @@
59 60 </md-button>
60 61 <md-button ng-show="!vm.displaySearchMode()" hide-xs hide-sm class="md-icon-button" ng-click="vm.toggleFullscreen()" aria-label="{{ 'fullscreen.toggle' | translate }}">
61 62 <ng-md-icon icon="{{vm.Fullscreen.isEnabled() ? 'fullscreen_exit' : 'fullscreen'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
62   - </md-button>
63   - <div hide-xs hide-sm ng-show="!vm.displaySearchMode()" class="tb-user-info" layout="row">
64   - <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon>
65   - <div layout="column">
66   - <span class="tb-user-display-name">{{vm.userDisplayName()}}</span>
67   - <span class="tb-user-authority">{{vm.authorityName()}}</span>
68   - </div>
69   - </div>
70   - <md-menu md-position-mode="target-right target">
71   - <md-button class="md-icon-button" aria-label="{{ 'home.open-user-menu' | translate }}" ng-click="$mdOpenMenu($event)">
72   - <md-icon md-menu-origin aria-label="{{ 'home.open-user-menu' | translate }}" class="material-icons">more_vert</md-icon>
73   - </md-button>
74   - <md-menu-content width="4">
75   - <md-menu-item>
76   - <md-button ng-click="vm.openProfile()">
77   - <md-icon md-menu-align-target aria-label="{{ 'home.profile' | translate }}" class="material-icons">account_circle</md-icon>
78   - <span translate>home.profile</span>
79   - </md-button>
80   - </md-menu-item>
81   - <md-menu-item>
82   - <md-button ng-click="vm.logout()">
83   - <md-icon md-menu-align-target aria-label="{{ 'home.logout' | translate }}" class="material-icons">exit_to_app</md-icon>
84   - <span translate>home.logout</span>
85   - </md-button>
86   - </md-menu-item>
87   - </md-menu-content>
88   - </md-menu>
  63 + </md-button>
  64 + <tb-user-menu
  65 + display-user-info="!vm.displaySearchMode()">
  66 + </tb-user-menu>
89 67 </div>
90 68 </md-toolbar>
91 69 <md-progress-linear class="md-warn" style="z-index: 10; max-height: 0px; width: 100%;" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>
... ...
... ... @@ -28,6 +28,8 @@ import thingsboardApiUser from '../api/user.service';
28 28 import thingsboardNoAnimate from '../components/no-animate.directive';
29 29 import thingsboardSideMenu from '../components/side-menu.directive';
30 30
  31 +import thingsboardUserMenu from './user-menu.directive';
  32 +
31 33 import thingsboardTenant from '../tenant';
32 34 import thingsboardCustomer from '../customer';
33 35 import thingsboardUser from '../user';
... ... @@ -54,6 +56,7 @@ export default angular.module('thingsboard.home', [
54 56 'ncy-angular-breadcrumb',
55 57 thingsboardMenu,
56 58 thingsboardHomeLinks,
  59 + thingsboardUserMenu,
57 60 thingsboardTenant,
58 61 thingsboardCustomer,
59 62 thingsboardUser,
... ...
  1 +/*
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import './user-menu.scss';
  18 +
  19 +/* eslint-disable import/no-unresolved, import/default */
  20 +
  21 +import userMenuTemplate from './user-menu.tpl.html';
  22 +
  23 +/* eslint-enable import/no-unresolved, import/default */
  24 +
  25 +export default angular.module('thingsboard.directives.usermenu', [])
  26 + .directive('tbUserMenu', UserMenu)
  27 + .name;
  28 +
  29 +/*@ngInject*/
  30 +function UserMenu() {
  31 + return {
  32 + restrict: "E",
  33 + scope: true,
  34 + bindToController: {
  35 + displayUserInfo: '=',
  36 + },
  37 + controller: UserMenuController,
  38 + controllerAs: 'vm',
  39 + templateUrl: userMenuTemplate
  40 + };
  41 +}
  42 +
  43 +/*@ngInject*/
  44 +function UserMenuController($scope, userService, $translate, $state) {
  45 +
  46 + var vm = this;
  47 +
  48 + var dashboardUser = userService.getCurrentUser();
  49 +
  50 + vm.authorityName = authorityName;
  51 + vm.displaySearchMode = displaySearchMode;
  52 + vm.logout = logout;
  53 + vm.openProfile = openProfile;
  54 + vm.userDisplayName = userDisplayName;
  55 +
  56 + function displaySearchMode() {
  57 + return $scope.searchConfig.searchEnabled &&
  58 + $scope.searchConfig.showSearch;
  59 + }
  60 +
  61 + function authorityName() {
  62 + var name = "user.anonymous";
  63 + if (dashboardUser) {
  64 + var authority = dashboardUser.authority;
  65 + if (authority === 'SYS_ADMIN') {
  66 + name = 'user.sys-admin';
  67 + } else if (authority === 'TENANT_ADMIN') {
  68 + name = 'user.tenant-admin';
  69 + } else if (authority === 'CUSTOMER_USER') {
  70 + name = 'user.customer';
  71 + }
  72 + }
  73 + return $translate.instant(name);
  74 + }
  75 +
  76 + function userDisplayName() {
  77 + var name = "";
  78 + if (dashboardUser) {
  79 + if ((dashboardUser.firstName && dashboardUser.firstName.length > 0) ||
  80 + (dashboardUser.lastName && dashboardUser.lastName.length > 0)) {
  81 + if (dashboardUser.firstName) {
  82 + name += dashboardUser.firstName;
  83 + }
  84 + if (dashboardUser.lastName) {
  85 + if (name.length > 0) {
  86 + name += " ";
  87 + }
  88 + name += dashboardUser.lastName;
  89 + }
  90 + } else {
  91 + name = dashboardUser.email;
  92 + }
  93 + }
  94 + return name;
  95 + }
  96 +
  97 + function openProfile() {
  98 + $state.go('home.profile');
  99 + }
  100 +
  101 + function logout() {
  102 + userService.logout();
  103 + }
  104 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +div.tb-user-info {
  18 + line-height: 1.5;
  19 + span {
  20 + text-transform: none;
  21 + text-align: left;
  22 + }
  23 + span.tb-user-display-name {
  24 + font-size: 0.800rem;
  25 + font-weight: 300;
  26 + letter-spacing: 0.008em;
  27 + }
  28 + span.tb-user-authority {
  29 + font-size: 0.800rem;
  30 + font-weight: 300;
  31 + letter-spacing: 0.005em;
  32 + opacity: 0.8;
  33 + }
  34 +}
  35 +
  36 +md-icon.tb-mini-avatar {
  37 + margin: auto 8px;
  38 + font-size: 36px;
  39 + height: 36px;
  40 + width: 36px;
  41 +}
... ...
  1 +<section layout="row">
  2 + <div hide-xs hide-sm ng-show="vm.displayUserInfo" class="tb-user-info" layout="row">
  3 + <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon>
  4 + <div layout="column">
  5 + <span class="tb-user-display-name">{{vm.userDisplayName()}}</span>
  6 + <span class="tb-user-authority">{{vm.authorityName()}}</span>
  7 + </div>
  8 + </div>
  9 + <md-menu md-position-mode="target-right target">
  10 + <md-button class="md-icon-button" aria-label="{{ 'home.open-user-menu' | translate }}" ng-click="$mdOpenMenu($event)">
  11 + <md-icon md-menu-origin aria-label="{{ 'home.open-user-menu' | translate }}" class="material-icons">more_vert</md-icon>
  12 + </md-button>
  13 + <md-menu-content width="4">
  14 + <md-menu-item>
  15 + <md-button ng-click="vm.openProfile()">
  16 + <md-icon md-menu-align-target aria-label="{{ 'home.profile' | translate }}" class="material-icons">account_circle</md-icon>
  17 + <span translate>home.profile</span>
  18 + </md-button>
  19 + </md-menu-item>
  20 + <md-menu-item>
  21 + <md-button ng-click="vm.logout()">
  22 + <md-icon md-menu-align-target aria-label="{{ 'home.logout' | translate }}" class="material-icons">exit_to_app</md-icon>
  23 + <span translate>home.logout</span>
  24 + </md-button>
  25 + </md-menu-item>
  26 + </md-menu-content>
  27 + </md-menu>
  28 +</section>
... ...
... ... @@ -632,7 +632,9 @@ export default angular.module('thingsboard.locale', [])
632 632 "email-required": "Email is required.",
633 633 "first-name": "First Name",
634 634 "last-name": "Last Name",
635   - "description": "Description"
  635 + "description": "Description",
  636 + "default-dashboard": "Default dashboard",
  637 + "always-fullscreen": "Always fullscreen"
636 638 },
637 639 "value": {
638 640 "type": "Value type",
... ...
... ... @@ -63,7 +63,7 @@ function Menu(userService, $state, $rootScope) {
63 63 {
64 64 name: 'home.home',
65 65 type: 'link',
66   - state: 'home',
  66 + state: 'home.links',
67 67 icon: 'home'
68 68 },
69 69 {
... ... @@ -167,7 +167,7 @@ function Menu(userService, $state, $rootScope) {
167 167 {
168 168 name: 'home.home',
169 169 type: 'link',
170   - state: 'home',
  170 + state: 'home.links',
171 171 icon: 'home'
172 172 },
173 173 {
... ... @@ -264,7 +264,7 @@ function Menu(userService, $state, $rootScope) {
264 264 {
265 265 name: 'home.home',
266 266 type: 'link',
267   - state: 'home',
  267 + state: 'home.links',
268 268 icon: 'home'
269 269 },
270 270 {
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +@import '../../scss/constants';
  18 +
  19 +.tb-default-dashboard {
  20 + .tb-default-dashboard-label {
  21 + padding-bottom: 8px;
  22 + }
  23 + tb-dashboard-select {
  24 + @media (min-width: $layout-breakpoint-gt-sm) {
  25 + padding-right: 12px;
  26 + }
  27 + @media (max-width: $layout-breakpoint-gt-sm) {
  28 + padding-bottom: 12px;
  29 + }
  30 + }
  31 +}
\ No newline at end of file
... ...
... ... @@ -43,5 +43,20 @@
43 43 <label translate>user.description</label>
44 44 <textarea ng-model="user.additionalInfo.description" rows="2"></textarea>
45 45 </md-input-container>
  46 + <section class="tb-default-dashboard" flex layout="column"ng-show="isCustomerUser()">
  47 + <span class="tb-default-dashboard-label" ng-class="{'tb-disabled-label': loading || !isEdit}" translate>user.default-dashboard</span>
  48 + <section flex layout="column" layout-gt-sm="row">
  49 + <tb-dashboard-select flex
  50 + the-form="theForm"
  51 + ng-model="defaultDashboard"
  52 + dashboards-scope="customer"
  53 + customer-id="user.customerId.id"
  54 + select-first-dashboard="false">
  55 + </tb-dashboard-select>
  56 + <md-checkbox ng-disabled="loading || !isEdit" flex aria-label="{{ 'user.always-fullscreen' | translate }}"
  57 + ng-model="user.additionalInfo.defaultDashboardFullscreen">{{ 'user.always-fullscreen' | translate }}
  58 + </md-checkbox>
  59 + </section>
  60 + </section>
46 61 </fieldset>
47 62 </md-content>
... ...
... ... @@ -13,6 +13,9 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
  16 +
  17 +import './user-fieldset.scss';
  18 +
16 19 /* eslint-disable import/no-unresolved, import/default */
17 20
18 21 import userFieldsetTemplate from './user-fieldset.tpl.html';
... ... @@ -20,10 +23,40 @@ import userFieldsetTemplate from './user-fieldset.tpl.html';
20 23 /* eslint-enable import/no-unresolved, import/default */
21 24
22 25 /*@ngInject*/
23   -export default function UserDirective($compile, $templateCache) {
  26 +export default function UserDirective($compile, $templateCache, dashboardService) {
24 27 var linker = function (scope, element) {
25 28 var template = $templateCache.get(userFieldsetTemplate);
26 29 element.html(template);
  30 +
  31 + scope.isCustomerUser = function() {
  32 + return scope.user && scope.user.authority === 'CUSTOMER_USER';
  33 + }
  34 +
  35 + scope.$watch('user', function(newUser, prevUser) {
  36 + if (!angular.equals(newUser, prevUser) && newUser) {
  37 + scope.defaultDashboard = null;
  38 + if (scope.isCustomerUser() && scope.user.additionalInfo &&
  39 + scope.user.additionalInfo.defaultDashboardId) {
  40 + dashboardService.getDashboard(scope.user.additionalInfo.defaultDashboardId).then(
  41 + function(dashboard) {
  42 + scope.defaultDashboard = dashboard;
  43 + }
  44 + )
  45 + }
  46 + }
  47 + });
  48 +
  49 + scope.$watch('defaultDashboard', function(newDashboard, prevDashboard) {
  50 + if (!angular.equals(newDashboard, prevDashboard)) {
  51 + if (scope.isCustomerUser()) {
  52 + if (!scope.user.additionalInfo) {
  53 + scope.user.additionalInfo = {};
  54 + }
  55 + scope.user.additionalInfo.defaultDashboardId = newDashboard ? newDashboard.id.id : null;
  56 + }
  57 + }
  58 + });
  59 +
27 60 $compile(element.contents())(scope);
28 61 }
29 62 return {
... ...