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 | 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, | ... | ... |
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 | +} | |
\ No newline at end of file | ... | ... |
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 | 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 | { | ... | ... |
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 | +} | |
\ 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 { | ... | ... |