Commit 88bb7f31b0f8b78a335c541df2ed6f4bc71c0065
1 parent
207642e8
UI: Ability to set default dashboard for customer user
Showing
18 changed files
with
382 additions
and
155 deletions
@@ -22,8 +22,9 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin, | @@ -22,8 +22,9 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin, | ||
22 | .name; | 22 | .name; |
23 | 23 | ||
24 | /*@ngInject*/ | 24 | /*@ngInject*/ |
25 | -function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | 25 | +function UserService($http, $q, $rootScope, store, jwtHelper, $translate, $state) { |
26 | var currentUser = null, | 26 | var currentUser = null, |
27 | + currentUserDetails = null, | ||
27 | userLoaded = false; | 28 | userLoaded = false; |
28 | 29 | ||
29 | var refreshTokenQueue = []; | 30 | var refreshTokenQueue = []; |
@@ -47,6 +48,8 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | @@ -47,6 +48,8 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | ||
47 | refreshJwtToken: refreshJwtToken, | 48 | refreshJwtToken: refreshJwtToken, |
48 | refreshTokenPending: refreshTokenPending, | 49 | refreshTokenPending: refreshTokenPending, |
49 | updateAuthorizationHeader: updateAuthorizationHeader, | 50 | updateAuthorizationHeader: updateAuthorizationHeader, |
51 | + gotoDefaultPlace: gotoDefaultPlace, | ||
52 | + forceDefaultPlace: forceDefaultPlace, | ||
50 | logout: logout | 53 | logout: logout |
51 | } | 54 | } |
52 | 55 | ||
@@ -86,6 +89,7 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | @@ -86,6 +89,7 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | ||
86 | 89 | ||
87 | function setUserFromJwtToken(jwtToken, refreshToken, notify, doLogout) { | 90 | function setUserFromJwtToken(jwtToken, refreshToken, notify, doLogout) { |
88 | currentUser = null; | 91 | currentUser = null; |
92 | + currentUserDetails = null; | ||
89 | if (!jwtToken) { | 93 | if (!jwtToken) { |
90 | clearTokenData(); | 94 | clearTokenData(); |
91 | if (notify) { | 95 | if (notify) { |
@@ -222,7 +226,25 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | @@ -222,7 +226,25 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | ||
222 | } else if (currentUser) { | 226 | } else if (currentUser) { |
223 | currentUser.authority = "ANONYMOUS"; | 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 | }, function fail() { | 248 | }, function fail() { |
227 | deferred.reject(); | 249 | deferred.reject(); |
228 | }); | 250 | }); |
@@ -331,4 +353,40 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | @@ -331,4 +353,40 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) { | ||
331 | return deferred.promise; | 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,7 +38,7 @@ export default function AppConfig($provide, | ||
38 | 38 | ||
39 | injectTapEventPlugin(); | 39 | injectTapEventPlugin(); |
40 | $locationProvider.html5Mode(true); | 40 | $locationProvider.html5Mode(true); |
41 | - $urlRouterProvider.otherwise('/home'); | 41 | + //$urlRouterProvider.otherwise('/home'); |
42 | storeProvider.setCaching(false); | 42 | storeProvider.setCaching(false); |
43 | 43 | ||
44 | $translateProvider.useSanitizeValueStrategy('sanitize'); | 44 | $translateProvider.useSanitizeValueStrategy('sanitize'); |
@@ -36,6 +36,8 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | @@ -36,6 +36,8 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | ||
36 | 36 | ||
37 | initWatchers(); | 37 | initWatchers(); |
38 | 38 | ||
39 | + checkCurrentState(); | ||
40 | + | ||
39 | function initWatchers() { | 41 | function initWatchers() { |
40 | $rootScope.unauthenticatedHandle = $rootScope.$on('unauthenticated', function (event, doLogout) { | 42 | $rootScope.unauthenticatedHandle = $rootScope.$on('unauthenticated', function (event, doLogout) { |
41 | if (doLogout) { | 43 | if (doLogout) { |
@@ -56,22 +58,27 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | @@ -56,22 +58,27 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | ||
56 | $rootScope.stateChangeStartHandle = $rootScope.$on('$stateChangeStart', function (evt, to, params) { | 58 | $rootScope.stateChangeStartHandle = $rootScope.$on('$stateChangeStart', function (evt, to, params) { |
57 | if (userService.isUserLoaded() === true) { | 59 | if (userService.isUserLoaded() === true) { |
58 | if (userService.isAuthenticated()) { | 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 | evt.preventDefault(); | 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 | } else { | 78 | } else { |
72 | if (to.module === 'private') { | 79 | if (to.module === 'private') { |
73 | evt.preventDefault(); | 80 | evt.preventDefault(); |
74 | - if (to.url === '/home') { | 81 | + if (to.url === '/home' || to.url === '/') { |
75 | $state.go('login', params); | 82 | $state.go('login', params); |
76 | } else { | 83 | } else { |
77 | showUnauthorizedDialog(); | 84 | showUnauthorizedDialog(); |
@@ -80,6 +87,9 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | @@ -80,6 +87,9 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | ||
80 | } | 87 | } |
81 | } else { | 88 | } else { |
82 | evt.preventDefault(); | 89 | evt.preventDefault(); |
90 | + if ($rootScope.userLoadedHandle) { | ||
91 | + $rootScope.userLoadedHandle(); | ||
92 | + } | ||
83 | $rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () { | 93 | $rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () { |
84 | $rootScope.userLoadedHandle(); | 94 | $rootScope.userLoadedHandle(); |
85 | $state.go(to.name, params); | 95 | $state.go(to.name, params); |
@@ -102,23 +112,26 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | @@ -102,23 +112,26 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi | ||
102 | 112 | ||
103 | function checkCurrentState() { | 113 | function checkCurrentState() { |
104 | if (userService.isUserLoaded() === true) { | 114 | if (userService.isUserLoaded() === true) { |
105 | - var module = $state.$current.module; | ||
106 | if (userService.isAuthenticated()) { | 115 | if (userService.isAuthenticated()) { |
107 | - if ($state.$current.module === 'public') { | ||
108 | - $state.go('home'); | ||
109 | - } | 116 | + gotoDefaultPlace(); |
110 | } else { | 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 | } else { | 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 | function showUnauthorizedDialog() { | 135 | function showUnauthorizedDialog() { |
123 | if (unauthorizedDialog === null) { | 136 | if (unauthorizedDialog === null) { |
124 | $translate(['access.unauthorized-access', | 137 | $translate(['access.unauthorized-access', |
@@ -40,27 +40,19 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer | @@ -40,27 +40,19 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer | ||
40 | scope.dashboard = null; | 40 | scope.dashboard = null; |
41 | scope.dashboardSearchText = ''; | 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 | scope.fetchDashboards = function(searchText) { | 43 | scope.fetchDashboards = function(searchText) { |
59 | var pageLink = {limit: 10, textSearch: searchText}; | 44 | var pageLink = {limit: 10, textSearch: searchText}; |
60 | 45 | ||
61 | var deferred = $q.defer(); | 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 | deferred.resolve(result.data); | 56 | deferred.resolve(result.data); |
65 | }, function fail() { | 57 | }, function fail() { |
66 | deferred.reject(); | 58 | deferred.reject(); |
@@ -79,6 +71,8 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer | @@ -79,6 +71,8 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer | ||
79 | ngModelCtrl.$render = function () { | 71 | ngModelCtrl.$render = function () { |
80 | if (ngModelCtrl.$viewValue) { | 72 | if (ngModelCtrl.$viewValue) { |
81 | scope.dashboard = ngModelCtrl.$viewValue; | 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,6 +100,7 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer | ||
106 | link: linker, | 100 | link: linker, |
107 | scope: { | 101 | scope: { |
108 | dashboardsScope: '@', | 102 | dashboardsScope: '@', |
103 | + customerId: '=', | ||
109 | theForm: '=?', | 104 | theForm: '=?', |
110 | tbRequired: '=?', | 105 | tbRequired: '=?', |
111 | selectFirstDashboard: '=' | 106 | selectFirstDashboard: '=' |
@@ -108,10 +108,10 @@ section.tb-dashboard-toolbar { | @@ -108,10 +108,10 @@ section.tb-dashboard-toolbar { | ||
108 | } | 108 | } |
109 | } | 109 | } |
110 | .md-fab-toolbar-wrapper { | 110 | .md-fab-toolbar-wrapper { |
111 | - height: 40px; | 111 | + height: 50px; |
112 | md-toolbar { | 112 | md-toolbar { |
113 | - min-height: 36px; | ||
114 | - height: 36px; | 113 | + min-height: 46px; |
114 | + height: 46px; | ||
115 | md-fab-actions { | 115 | md-fab-actions { |
116 | font-size: 16px; | 116 | font-size: 16px; |
117 | margin-top: 0px; | 117 | margin-top: 0px; |
@@ -126,7 +126,7 @@ section.tb-dashboard-toolbar { | @@ -126,7 +126,7 @@ section.tb-dashboard-toolbar { | ||
126 | 126 | ||
127 | .tb-dashboard-container { | 127 | .tb-dashboard-container { |
128 | &.tb-dashboard-toolbar-opened { | 128 | &.tb-dashboard-toolbar-opened { |
129 | - margin-top: 40px; | 129 | + margin-top: 50px; |
130 | @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2)); | 130 | @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2)); |
131 | } | 131 | } |
132 | &.tb-dashboard-toolbar-closed { | 132 | &.tb-dashboard-toolbar-closed { |
@@ -15,8 +15,8 @@ | @@ -15,8 +15,8 @@ | ||
15 | limitations under the License. | 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 | ng-style="{'background-color': vm.dashboard.configuration.gridSettings.backgroundColor, | 20 | ng-style="{'background-color': vm.dashboard.configuration.gridSettings.backgroundColor, |
21 | 'background-image': 'url('+vm.dashboard.configuration.gridSettings.backgroundImageUrl+')', | 21 | 'background-image': 'url('+vm.dashboard.configuration.gridSettings.backgroundImageUrl+')', |
22 | 'background-repeat': 'no-repeat', | 22 | 'background-repeat': 'no-repeat', |
@@ -47,6 +47,8 @@ | @@ -47,6 +47,8 @@ | ||
47 | aria-label="{{ 'fullscreen.fullscreen' | translate }}" | 47 | aria-label="{{ 'fullscreen.fullscreen' | translate }}" |
48 | class="md-icon-button"> | 48 | class="md-icon-button"> |
49 | </md-button> | 49 | </md-button> |
50 | + <tb-user-menu ng-show="forceFullscreen" display-user-info="true"> | ||
51 | + </tb-user-menu> | ||
50 | <tb-timewindow direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow"> | 52 | <tb-timewindow direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow"> |
51 | </tb-timewindow> | 53 | </tb-timewindow> |
52 | <tb-aliases-device-select ng-show="!vm.isEdit" | 54 | <tb-aliases-device-select ng-show="!vm.isEdit" |
@@ -26,9 +26,7 @@ import logoSvg from '../../svg/logo_title_white.svg'; | @@ -26,9 +26,7 @@ import logoSvg from '../../svg/logo_title_white.svg'; | ||
26 | 26 | ||
27 | /*@ngInject*/ | 27 | /*@ngInject*/ |
28 | export default function HomeController(loginService, userService, deviceService, Fullscreen, $scope, $element, $rootScope, $document, $state, | 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 | var siteSideNav = $('.tb-site-sidenav', $element); | 31 | var siteSideNav = $('.tb-site-sidenav', $element); |
34 | 32 | ||
@@ -48,15 +46,11 @@ export default function HomeController(loginService, userService, deviceService, | @@ -48,15 +46,11 @@ export default function HomeController(loginService, userService, deviceService, | ||
48 | vm.isShowSidenav = false; | 46 | vm.isShowSidenav = false; |
49 | vm.isLockSidenav = false; | 47 | vm.isLockSidenav = false; |
50 | 48 | ||
51 | - vm.authorityName = authorityName; | ||
52 | vm.displaySearchMode = displaySearchMode; | 49 | vm.displaySearchMode = displaySearchMode; |
53 | - vm.logout = logout; | ||
54 | - vm.openProfile = openProfile; | ||
55 | vm.openSidenav = openSidenav; | 50 | vm.openSidenav = openSidenav; |
56 | vm.searchTextUpdated = searchTextUpdated; | 51 | vm.searchTextUpdated = searchTextUpdated; |
57 | vm.sidenavClicked = sidenavClicked; | 52 | vm.sidenavClicked = sidenavClicked; |
58 | vm.toggleFullscreen = toggleFullscreen; | 53 | vm.toggleFullscreen = toggleFullscreen; |
59 | - vm.userDisplayName = userDisplayName; | ||
60 | 54 | ||
61 | $scope.$on('$stateChangeSuccess', function (evt, to, toParams, from) { | 55 | $scope.$on('$stateChangeSuccess', function (evt, to, toParams, from) { |
62 | if (angular.isDefined(to.data.searchEnabled)) { | 56 | if (angular.isDefined(to.data.searchEnabled)) { |
@@ -106,50 +100,6 @@ export default function HomeController(loginService, userService, deviceService, | @@ -106,50 +100,6 @@ export default function HomeController(loginService, userService, deviceService, | ||
106 | $scope.$broadcast('searchTextUpdated'); | 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 | function openSidenav() { | 103 | function openSidenav() { |
154 | vm.isShowSidenav = true; | 104 | vm.isShowSidenav = true; |
155 | } | 105 | } |
@@ -53,37 +53,11 @@ md-sidenav.tb-site-sidenav { | @@ -53,37 +53,11 @@ md-sidenav.tb-site-sidenav { | ||
53 | width: 250px; | 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 | md-icon.tb-logo-title { | 56 | md-icon.tb-logo-title { |
64 | height: 36px; | 57 | height: 36px; |
65 | width: 200px; | 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 | .tb-nav-header { | 61 | .tb-nav-header { |
88 | flex-shrink: 0; | 62 | flex-shrink: 0; |
89 | z-index: 2; | 63 | z-index: 2; |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | <md-sidenav class="tb-site-sidenav md-sidenav-left md-whiteframe-z2" | 18 | <md-sidenav class="tb-site-sidenav md-sidenav-left md-whiteframe-z2" |
19 | + ng-show="!forceFullscreen" | ||
19 | hide-print="" | 20 | hide-print="" |
20 | md-component-id="left" | 21 | md-component-id="left" |
21 | aria-label="Toggle Nav" | 22 | aria-label="Toggle Nav" |
@@ -59,33 +60,10 @@ | @@ -59,33 +60,10 @@ | ||
59 | </md-button> | 60 | </md-button> |
60 | <md-button ng-show="!vm.displaySearchMode()" hide-xs hide-sm class="md-icon-button" ng-click="vm.toggleFullscreen()" aria-label="{{ 'fullscreen.toggle' | translate }}"> | 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 | <ng-md-icon icon="{{vm.Fullscreen.isEnabled() ? 'fullscreen_exit' : 'fullscreen'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon> | 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 | </div> | 67 | </div> |
90 | </md-toolbar> | 68 | </md-toolbar> |
91 | <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> | 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,6 +28,8 @@ import thingsboardApiUser from '../api/user.service'; | ||
28 | import thingsboardNoAnimate from '../components/no-animate.directive'; | 28 | import thingsboardNoAnimate from '../components/no-animate.directive'; |
29 | import thingsboardSideMenu from '../components/side-menu.directive'; | 29 | import thingsboardSideMenu from '../components/side-menu.directive'; |
30 | 30 | ||
31 | +import thingsboardUserMenu from './user-menu.directive'; | ||
32 | + | ||
31 | import thingsboardTenant from '../tenant'; | 33 | import thingsboardTenant from '../tenant'; |
32 | import thingsboardCustomer from '../customer'; | 34 | import thingsboardCustomer from '../customer'; |
33 | import thingsboardUser from '../user'; | 35 | import thingsboardUser from '../user'; |
@@ -54,6 +56,7 @@ export default angular.module('thingsboard.home', [ | @@ -54,6 +56,7 @@ export default angular.module('thingsboard.home', [ | ||
54 | 'ncy-angular-breadcrumb', | 56 | 'ncy-angular-breadcrumb', |
55 | thingsboardMenu, | 57 | thingsboardMenu, |
56 | thingsboardHomeLinks, | 58 | thingsboardHomeLinks, |
59 | + thingsboardUserMenu, | ||
57 | thingsboardTenant, | 60 | thingsboardTenant, |
58 | thingsboardCustomer, | 61 | thingsboardCustomer, |
59 | thingsboardUser, | 62 | thingsboardUser, |
ui/src/app/layout/user-menu.directive.js
0 → 100644
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 | +} |
ui/src/app/layout/user-menu.scss
0 → 100644
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 | +} |
ui/src/app/layout/user-menu.tpl.html
0 → 100644
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,7 +632,9 @@ export default angular.module('thingsboard.locale', []) | ||
632 | "email-required": "Email is required.", | 632 | "email-required": "Email is required.", |
633 | "first-name": "First Name", | 633 | "first-name": "First Name", |
634 | "last-name": "Last Name", | 634 | "last-name": "Last Name", |
635 | - "description": "Description" | 635 | + "description": "Description", |
636 | + "default-dashboard": "Default dashboard", | ||
637 | + "always-fullscreen": "Always fullscreen" | ||
636 | }, | 638 | }, |
637 | "value": { | 639 | "value": { |
638 | "type": "Value type", | 640 | "type": "Value type", |
@@ -63,7 +63,7 @@ function Menu(userService, $state, $rootScope) { | @@ -63,7 +63,7 @@ function Menu(userService, $state, $rootScope) { | ||
63 | { | 63 | { |
64 | name: 'home.home', | 64 | name: 'home.home', |
65 | type: 'link', | 65 | type: 'link', |
66 | - state: 'home', | 66 | + state: 'home.links', |
67 | icon: 'home' | 67 | icon: 'home' |
68 | }, | 68 | }, |
69 | { | 69 | { |
@@ -167,7 +167,7 @@ function Menu(userService, $state, $rootScope) { | @@ -167,7 +167,7 @@ function Menu(userService, $state, $rootScope) { | ||
167 | { | 167 | { |
168 | name: 'home.home', | 168 | name: 'home.home', |
169 | type: 'link', | 169 | type: 'link', |
170 | - state: 'home', | 170 | + state: 'home.links', |
171 | icon: 'home' | 171 | icon: 'home' |
172 | }, | 172 | }, |
173 | { | 173 | { |
@@ -264,7 +264,7 @@ function Menu(userService, $state, $rootScope) { | @@ -264,7 +264,7 @@ function Menu(userService, $state, $rootScope) { | ||
264 | { | 264 | { |
265 | name: 'home.home', | 265 | name: 'home.home', |
266 | type: 'link', | 266 | type: 'link', |
267 | - state: 'home', | 267 | + state: 'home.links', |
268 | icon: 'home' | 268 | icon: 'home' |
269 | }, | 269 | }, |
270 | { | 270 | { |
ui/src/app/user/user-fieldset.scss
0 → 100644
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 | +} |
@@ -43,5 +43,20 @@ | @@ -43,5 +43,20 @@ | ||
43 | <label translate>user.description</label> | 43 | <label translate>user.description</label> |
44 | <textarea ng-model="user.additionalInfo.description" rows="2"></textarea> | 44 | <textarea ng-model="user.additionalInfo.description" rows="2"></textarea> |
45 | </md-input-container> | 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 | </fieldset> | 61 | </fieldset> |
47 | </md-content> | 62 | </md-content> |
@@ -13,6 +13,9 @@ | @@ -13,6 +13,9 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | + | ||
17 | +import './user-fieldset.scss'; | ||
18 | + | ||
16 | /* eslint-disable import/no-unresolved, import/default */ | 19 | /* eslint-disable import/no-unresolved, import/default */ |
17 | 20 | ||
18 | import userFieldsetTemplate from './user-fieldset.tpl.html'; | 21 | import userFieldsetTemplate from './user-fieldset.tpl.html'; |
@@ -20,10 +23,40 @@ import userFieldsetTemplate from './user-fieldset.tpl.html'; | @@ -20,10 +23,40 @@ import userFieldsetTemplate from './user-fieldset.tpl.html'; | ||
20 | /* eslint-enable import/no-unresolved, import/default */ | 23 | /* eslint-enable import/no-unresolved, import/default */ |
21 | 24 | ||
22 | /*@ngInject*/ | 25 | /*@ngInject*/ |
23 | -export default function UserDirective($compile, $templateCache) { | 26 | +export default function UserDirective($compile, $templateCache, dashboardService) { |
24 | var linker = function (scope, element) { | 27 | var linker = function (scope, element) { |
25 | var template = $templateCache.get(userFieldsetTemplate); | 28 | var template = $templateCache.get(userFieldsetTemplate); |
26 | element.html(template); | 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 | $compile(element.contents())(scope); | 60 | $compile(element.contents())(scope); |
28 | } | 61 | } |
29 | return { | 62 | return { |