thingsboard-memoizeit
Changes
ui/src/app/api/user.service.js 62(+60 -2)
ui/src/app/app.config.js 2(+1 -1)
ui/src/app/app.run.js 55(+34 -21)
ui/src/app/dashboard/dashboard.scss 8(+4 -4)
ui/src/app/layout/home.controller.js 52(+1 -51)
ui/src/app/layout/home.scss 26(+0 -26)
ui/src/app/layout/home.tpl.html 32(+5 -27)
ui/src/app/layout/index.js 3(+3 -0)
ui/src/app/layout/user-menu.directive.js 104(+104 -0)
ui/src/app/layout/user-menu.scss 41(+41 -0)
ui/src/app/layout/user-menu.tpl.html 28(+28 -0)
ui/src/app/locale/locale.constant.js 4(+3 -1)
ui/src/app/services/menu.service.js 6(+3 -3)
ui/src/app/user/user.directive.js 35(+34 -1)
ui/src/app/user/user-fieldset.scss 31(+31 -0)
ui/src/app/user/user-fieldset.tpl.html 15(+15 -0)
Details
ui/src/app/api/user.service.js 62(+60 -2)
diff --git a/ui/src/app/api/user.service.js b/ui/src/app/api/user.service.js
index 8f87048..ea86cd6 100644
--- a/ui/src/app/api/user.service.js
+++ b/ui/src/app/api/user.service.js
@@ -22,8 +22,9 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin,
.name;
/*@ngInject*/
-function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
+function UserService($http, $q, $rootScope, store, jwtHelper, $translate, $state) {
var currentUser = null,
+ currentUserDetails = null,
userLoaded = false;
var refreshTokenQueue = [];
@@ -47,6 +48,8 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
refreshJwtToken: refreshJwtToken,
refreshTokenPending: refreshTokenPending,
updateAuthorizationHeader: updateAuthorizationHeader,
+ gotoDefaultPlace: gotoDefaultPlace,
+ forceDefaultPlace: forceDefaultPlace,
logout: logout
}
@@ -86,6 +89,7 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
function setUserFromJwtToken(jwtToken, refreshToken, notify, doLogout) {
currentUser = null;
+ currentUserDetails = null;
if (!jwtToken) {
clearTokenData();
if (notify) {
@@ -222,7 +226,25 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
} else if (currentUser) {
currentUser.authority = "ANONYMOUS";
}
- deferred.resolve();
+ if (currentUser.userId) {
+ getUser(currentUser.userId).then(
+ function success(user) {
+ currentUserDetails = user;
+ if (currentUserDetails.additionalInfo &&
+ currentUserDetails.additionalInfo.defaultDashboardFullscreen) {
+ $rootScope.forceFullscreen = currentUserDetails.additionalInfo.defaultDashboardFullscreen === true;
+ } else {
+ $rootScope.forceFullscreen = false;
+ }
+ deferred.resolve();
+ },
+ function fail() {
+ deferred.reject();
+ }
+ )
+ } else {
+ deferred.reject();
+ }
}, function fail() {
deferred.reject();
});
@@ -331,4 +353,40 @@ function UserService($http, $q, $rootScope, store, jwtHelper, $translate) {
return deferred.promise;
}
+ function forceDefaultPlace(to, params) {
+ if (currentUser && isAuthenticated()) {
+ if (currentUser.authority === 'CUSTOMER_USER') {
+ if (currentUserDetails &&
+ currentUserDetails.additionalInfo &&
+ currentUserDetails.additionalInfo.defaultDashboardId) {
+ if ($rootScope.forceFullscreen) {
+ if (to.name === 'home.profile') {
+ return false;
+ } else if (to.name !== 'home.dashboards.dashboard' && params.dashboardId !== currentUserDetails.additionalInfo.defaultDashboardId) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ function gotoDefaultPlace(params) {
+ if (currentUser && isAuthenticated()) {
+ var place = 'home.links';
+ if (currentUser.authority === 'CUSTOMER_USER') {
+ if (currentUserDetails &&
+ currentUserDetails.additionalInfo &&
+ currentUserDetails.additionalInfo.defaultDashboardId) {
+ place = 'home.dashboards.dashboard';
+ params = {dashboardId: currentUserDetails.additionalInfo.defaultDashboardId};
+ }
+ }
+ $state.go(place, params);
+ } else {
+ $state.go('login', params);
+ }
+ }
+
}
ui/src/app/app.config.js 2(+1 -1)
diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js
index bed6b0d..bde3525 100644
--- a/ui/src/app/app.config.js
+++ b/ui/src/app/app.config.js
@@ -38,7 +38,7 @@ export default function AppConfig($provide,
injectTapEventPlugin();
$locationProvider.html5Mode(true);
- $urlRouterProvider.otherwise('/home');
+ //$urlRouterProvider.otherwise('/home');
storeProvider.setCaching(false);
$translateProvider.useSanitizeValueStrategy('sanitize');
ui/src/app/app.run.js 55(+34 -21)
diff --git a/ui/src/app/app.run.js b/ui/src/app/app.run.js
index 057b413..ae932ec 100644
--- a/ui/src/app/app.run.js
+++ b/ui/src/app/app.run.js
@@ -36,6 +36,8 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
initWatchers();
+ checkCurrentState();
+
function initWatchers() {
$rootScope.unauthenticatedHandle = $rootScope.$on('unauthenticated', function (event, doLogout) {
if (doLogout) {
@@ -56,22 +58,27 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
$rootScope.stateChangeStartHandle = $rootScope.$on('$stateChangeStart', function (evt, to, params) {
if (userService.isUserLoaded() === true) {
if (userService.isAuthenticated()) {
- var authority = userService.getAuthority();
- if (to.module === 'public') {
- evt.preventDefault();
- $state.go('home', params);
- } else if (angular.isDefined(to.auth) &&
- to.auth.indexOf(authority) === -1) {
+ if (userService.forceDefaultPlace(to, params)) {
evt.preventDefault();
- showForbiddenDialog();
- } else if (to.redirectTo) {
- evt.preventDefault();
- $state.go(to.redirectTo, params)
+ gotoDefaultPlace(params);
+ } else {
+ var authority = userService.getAuthority();
+ if (to.module === 'public') {
+ evt.preventDefault();
+ gotoDefaultPlace(params);
+ } else if (angular.isDefined(to.auth) &&
+ to.auth.indexOf(authority) === -1) {
+ evt.preventDefault();
+ showForbiddenDialog();
+ } else if (to.redirectTo) {
+ evt.preventDefault();
+ $state.go(to.redirectTo, params)
+ }
}
} else {
if (to.module === 'private') {
evt.preventDefault();
- if (to.url === '/home') {
+ if (to.url === '/home' || to.url === '/') {
$state.go('login', params);
} else {
showUnauthorizedDialog();
@@ -80,6 +87,9 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
}
} else {
evt.preventDefault();
+ if ($rootScope.userLoadedHandle) {
+ $rootScope.userLoadedHandle();
+ }
$rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () {
$rootScope.userLoadedHandle();
$state.go(to.name, params);
@@ -102,23 +112,26 @@ export default function AppRun($rootScope, $window, $log, $state, $mdDialog, $fi
function checkCurrentState() {
if (userService.isUserLoaded() === true) {
- var module = $state.$current.module;
if (userService.isAuthenticated()) {
- if ($state.$current.module === 'public') {
- $state.go('home');
- }
+ gotoDefaultPlace();
} else {
- if (angular.isUndefined(module) || !module) {
- //$state.go('login');
- } else if ($state.$current.module === 'private') {
- showUnauthorizedDialog();
- }
+ $state.go('login');
}
} else {
- showUnauthorizedDialog();
+ if ($rootScope.userLoadedHandle) {
+ $rootScope.userLoadedHandle();
+ }
+ $rootScope.userLoadedHandle = $rootScope.$on('userLoaded', function () {
+ $rootScope.userLoadedHandle();
+ checkCurrentState();
+ });
}
}
+ function gotoDefaultPlace(params) {
+ userService.gotoDefaultPlace(params);
+ }
+
function showUnauthorizedDialog() {
if (unauthorizedDialog === null) {
$translate(['access.unauthorized-access',
diff --git a/ui/src/app/components/dashboard-select.directive.js b/ui/src/app/components/dashboard-select.directive.js
index 0f76258..7569698 100644
--- a/ui/src/app/components/dashboard-select.directive.js
+++ b/ui/src/app/components/dashboard-select.directive.js
@@ -40,27 +40,19 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
scope.dashboard = null;
scope.dashboardSearchText = '';
- scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
- if (angular.isDefined(scope.dashboardsScope)) {
- if (scope.dashboardsScope === 'customer') {
- scope.dashboardFetchFunction = dashboardService.getCustomerDashboards;
- } else {
- scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
- }
- } else {
- if (userService.getAuthority() === 'TENANT_ADMIN') {
- scope.dashboardFetchFunction = dashboardService.getTenantDashboards;
- } else if (userService.getAuthority() === 'CUSTOMER_USER') {
- scope.dashboardFetchFunction = dashboardService.getCustomerDashboards;
- }
- }
-
scope.fetchDashboards = function(searchText) {
var pageLink = {limit: 10, textSearch: searchText};
var deferred = $q.defer();
- scope.dashboardFetchFunction(pageLink).then(function success(result) {
+ var promise;
+ if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') {
+ promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink);
+ } else {
+ promise = dashboardService.getTenantDashboards(pageLink);
+ }
+
+ promise.then(function success(result) {
deferred.resolve(result.data);
}, function fail() {
deferred.reject();
@@ -79,6 +71,8 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
ngModelCtrl.$render = function () {
if (ngModelCtrl.$viewValue) {
scope.dashboard = ngModelCtrl.$viewValue;
+ } else {
+ scope.dashboard = null;
}
}
@@ -106,6 +100,7 @@ function DashboardSelect($compile, $templateCache, $q, dashboardService, userSer
link: linker,
scope: {
dashboardsScope: '@',
+ customerId: '=',
theForm: '=?',
tbRequired: '=?',
selectFirstDashboard: '='
ui/src/app/dashboard/dashboard.scss 8(+4 -4)
diff --git a/ui/src/app/dashboard/dashboard.scss b/ui/src/app/dashboard/dashboard.scss
index 1744a53..efc897e 100644
--- a/ui/src/app/dashboard/dashboard.scss
+++ b/ui/src/app/dashboard/dashboard.scss
@@ -108,10 +108,10 @@ section.tb-dashboard-toolbar {
}
}
.md-fab-toolbar-wrapper {
- height: 40px;
+ height: 50px;
md-toolbar {
- min-height: 36px;
- height: 36px;
+ min-height: 46px;
+ height: 46px;
md-fab-actions {
font-size: 16px;
margin-top: 0px;
@@ -126,7 +126,7 @@ section.tb-dashboard-toolbar {
.tb-dashboard-container {
&.tb-dashboard-toolbar-opened {
- margin-top: 40px;
+ margin-top: 50px;
@include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
}
&.tb-dashboard-toolbar-closed {
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index 7390485..a9a3625 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -15,8 +15,8 @@
limitations under the License.
-->
-<md-content flex tb-expand-fullscreen="vm.widgetEditMode || vm.iframeMode" expand-button-id="dashboard-expand-button"
- hide-expand-button="vm.widgetEditMode || vm.iframeMode" expand-tooltip-direction="bottom"
+<md-content flex tb-expand-fullscreen="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-button-id="dashboard-expand-button"
+ hide-expand-button="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-tooltip-direction="bottom"
ng-style="{'background-color': vm.dashboard.configuration.gridSettings.backgroundColor,
'background-image': 'url('+vm.dashboard.configuration.gridSettings.backgroundImageUrl+')',
'background-repeat': 'no-repeat',
@@ -47,6 +47,8 @@
aria-label="{{ 'fullscreen.fullscreen' | translate }}"
class="md-icon-button">
</md-button>
+ <tb-user-menu ng-show="forceFullscreen" display-user-info="true">
+ </tb-user-menu>
<tb-timewindow direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow">
</tb-timewindow>
<tb-aliases-device-select ng-show="!vm.isEdit"
ui/src/app/layout/home.controller.js 52(+1 -51)
diff --git a/ui/src/app/layout/home.controller.js b/ui/src/app/layout/home.controller.js
index bf113e6..290cacf 100644
--- a/ui/src/app/layout/home.controller.js
+++ b/ui/src/app/layout/home.controller.js
@@ -26,9 +26,7 @@ import logoSvg from '../../svg/logo_title_white.svg';
/*@ngInject*/
export default function HomeController(loginService, userService, deviceService, Fullscreen, $scope, $element, $rootScope, $document, $state,
- $log, $mdMedia, $animate, $timeout, $translate) {
-
- var dashboardUser = userService.getCurrentUser();
+ $log, $mdMedia, $animate, $timeout) {
var siteSideNav = $('.tb-site-sidenav', $element);
@@ -48,15 +46,11 @@ export default function HomeController(loginService, userService, deviceService,
vm.isShowSidenav = false;
vm.isLockSidenav = false;
- vm.authorityName = authorityName;
vm.displaySearchMode = displaySearchMode;
- vm.logout = logout;
- vm.openProfile = openProfile;
vm.openSidenav = openSidenav;
vm.searchTextUpdated = searchTextUpdated;
vm.sidenavClicked = sidenavClicked;
vm.toggleFullscreen = toggleFullscreen;
- vm.userDisplayName = userDisplayName;
$scope.$on('$stateChangeSuccess', function (evt, to, toParams, from) {
if (angular.isDefined(to.data.searchEnabled)) {
@@ -106,50 +100,6 @@ export default function HomeController(loginService, userService, deviceService,
$scope.$broadcast('searchTextUpdated');
}
- function authorityName() {
- var name = "user.anonymous";
- if (dashboardUser) {
- var authority = dashboardUser.authority;
- if (authority === 'SYS_ADMIN') {
- name = 'user.sys-admin';
- } else if (authority === 'TENANT_ADMIN') {
- name = 'user.tenant-admin';
- } else if (authority === 'CUSTOMER_USER') {
- name = 'user.customer';
- }
- }
- return $translate.instant(name);
- }
-
- function userDisplayName() {
- var name = "";
- if (dashboardUser) {
- if ((dashboardUser.firstName && dashboardUser.firstName.length > 0) ||
- (dashboardUser.lastName && dashboardUser.lastName.length > 0)) {
- if (dashboardUser.firstName) {
- name += dashboardUser.firstName;
- }
- if (dashboardUser.lastName) {
- if (name.length > 0) {
- name += " ";
- }
- name += dashboardUser.lastName;
- }
- } else {
- name = dashboardUser.email;
- }
- }
- return name;
- }
-
- function openProfile() {
- $state.go('home.profile');
- }
-
- function logout() {
- userService.logout();
- }
-
function openSidenav() {
vm.isShowSidenav = true;
}
ui/src/app/layout/home.scss 26(+0 -26)
diff --git a/ui/src/app/layout/home.scss b/ui/src/app/layout/home.scss
index dcbd662..edcdbc8 100644
--- a/ui/src/app/layout/home.scss
+++ b/ui/src/app/layout/home.scss
@@ -53,37 +53,11 @@ md-sidenav.tb-site-sidenav {
width: 250px;
}
-md-icon.tb-mini-avatar {
- margin: auto 8px;
- font-size: 36px;
- height: 36px;
- width: 36px;
-}
-
md-icon.tb-logo-title {
height: 36px;
width: 200px;
}
-div.tb-user-info {
- line-height: 1.5;
- span {
- text-transform: none;
- text-align: left;
- }
- span.tb-user-display-name {
- font-size: 0.800rem;
- font-weight: 300;
- letter-spacing: 0.008em;
- }
- span.tb-user-authority {
- font-size: 0.800rem;
- font-weight: 300;
- letter-spacing: 0.005em;
- opacity: 0.8;
- }
-}
-
.tb-nav-header {
flex-shrink: 0;
z-index: 2;
ui/src/app/layout/home.tpl.html 32(+5 -27)
diff --git a/ui/src/app/layout/home.tpl.html b/ui/src/app/layout/home.tpl.html
index 488e750..1f45ba7 100644
--- a/ui/src/app/layout/home.tpl.html
+++ b/ui/src/app/layout/home.tpl.html
@@ -16,6 +16,7 @@
-->
<md-sidenav class="tb-site-sidenav md-sidenav-left md-whiteframe-z2"
+ ng-show="!forceFullscreen"
hide-print=""
md-component-id="left"
aria-label="Toggle Nav"
@@ -59,33 +60,10 @@
</md-button>
<md-button ng-show="!vm.displaySearchMode()" hide-xs hide-sm class="md-icon-button" ng-click="vm.toggleFullscreen()" aria-label="{{ 'fullscreen.toggle' | translate }}">
<ng-md-icon icon="{{vm.Fullscreen.isEnabled() ? 'fullscreen_exit' : 'fullscreen'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
- </md-button>
- <div hide-xs hide-sm ng-show="!vm.displaySearchMode()" class="tb-user-info" layout="row">
- <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon>
- <div layout="column">
- <span class="tb-user-display-name">{{vm.userDisplayName()}}</span>
- <span class="tb-user-authority">{{vm.authorityName()}}</span>
- </div>
- </div>
- <md-menu md-position-mode="target-right target">
- <md-button class="md-icon-button" aria-label="{{ 'home.open-user-menu' | translate }}" ng-click="$mdOpenMenu($event)">
- <md-icon md-menu-origin aria-label="{{ 'home.open-user-menu' | translate }}" class="material-icons">more_vert</md-icon>
- </md-button>
- <md-menu-content width="4">
- <md-menu-item>
- <md-button ng-click="vm.openProfile()">
- <md-icon md-menu-align-target aria-label="{{ 'home.profile' | translate }}" class="material-icons">account_circle</md-icon>
- <span translate>home.profile</span>
- </md-button>
- </md-menu-item>
- <md-menu-item>
- <md-button ng-click="vm.logout()">
- <md-icon md-menu-align-target aria-label="{{ 'home.logout' | translate }}" class="material-icons">exit_to_app</md-icon>
- <span translate>home.logout</span>
- </md-button>
- </md-menu-item>
- </md-menu-content>
- </md-menu>
+ </md-button>
+ <tb-user-menu
+ display-user-info="!vm.displaySearchMode()">
+ </tb-user-menu>
</div>
</md-toolbar>
<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>
ui/src/app/layout/index.js 3(+3 -0)
diff --git a/ui/src/app/layout/index.js b/ui/src/app/layout/index.js
index 8cccd28..c747cbf 100644
--- a/ui/src/app/layout/index.js
+++ b/ui/src/app/layout/index.js
@@ -28,6 +28,8 @@ import thingsboardApiUser from '../api/user.service';
import thingsboardNoAnimate from '../components/no-animate.directive';
import thingsboardSideMenu from '../components/side-menu.directive';
+import thingsboardUserMenu from './user-menu.directive';
+
import thingsboardTenant from '../tenant';
import thingsboardCustomer from '../customer';
import thingsboardUser from '../user';
@@ -54,6 +56,7 @@ export default angular.module('thingsboard.home', [
'ncy-angular-breadcrumb',
thingsboardMenu,
thingsboardHomeLinks,
+ thingsboardUserMenu,
thingsboardTenant,
thingsboardCustomer,
thingsboardUser,
ui/src/app/layout/user-menu.directive.js 104(+104 -0)
diff --git a/ui/src/app/layout/user-menu.directive.js b/ui/src/app/layout/user-menu.directive.js
new file mode 100644
index 0000000..6d09e67
--- /dev/null
+++ b/ui/src/app/layout/user-menu.directive.js
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import './user-menu.scss';
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import userMenuTemplate from './user-menu.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+export default angular.module('thingsboard.directives.usermenu', [])
+ .directive('tbUserMenu', UserMenu)
+ .name;
+
+/*@ngInject*/
+function UserMenu() {
+ return {
+ restrict: "E",
+ scope: true,
+ bindToController: {
+ displayUserInfo: '=',
+ },
+ controller: UserMenuController,
+ controllerAs: 'vm',
+ templateUrl: userMenuTemplate
+ };
+}
+
+/*@ngInject*/
+function UserMenuController($scope, userService, $translate, $state) {
+
+ var vm = this;
+
+ var dashboardUser = userService.getCurrentUser();
+
+ vm.authorityName = authorityName;
+ vm.displaySearchMode = displaySearchMode;
+ vm.logout = logout;
+ vm.openProfile = openProfile;
+ vm.userDisplayName = userDisplayName;
+
+ function displaySearchMode() {
+ return $scope.searchConfig.searchEnabled &&
+ $scope.searchConfig.showSearch;
+ }
+
+ function authorityName() {
+ var name = "user.anonymous";
+ if (dashboardUser) {
+ var authority = dashboardUser.authority;
+ if (authority === 'SYS_ADMIN') {
+ name = 'user.sys-admin';
+ } else if (authority === 'TENANT_ADMIN') {
+ name = 'user.tenant-admin';
+ } else if (authority === 'CUSTOMER_USER') {
+ name = 'user.customer';
+ }
+ }
+ return $translate.instant(name);
+ }
+
+ function userDisplayName() {
+ var name = "";
+ if (dashboardUser) {
+ if ((dashboardUser.firstName && dashboardUser.firstName.length > 0) ||
+ (dashboardUser.lastName && dashboardUser.lastName.length > 0)) {
+ if (dashboardUser.firstName) {
+ name += dashboardUser.firstName;
+ }
+ if (dashboardUser.lastName) {
+ if (name.length > 0) {
+ name += " ";
+ }
+ name += dashboardUser.lastName;
+ }
+ } else {
+ name = dashboardUser.email;
+ }
+ }
+ return name;
+ }
+
+ function openProfile() {
+ $state.go('home.profile');
+ }
+
+ function logout() {
+ userService.logout();
+ }
+}
\ No newline at end of file
ui/src/app/layout/user-menu.scss 41(+41 -0)
diff --git a/ui/src/app/layout/user-menu.scss b/ui/src/app/layout/user-menu.scss
new file mode 100644
index 0000000..b90c8ee
--- /dev/null
+++ b/ui/src/app/layout/user-menu.scss
@@ -0,0 +1,41 @@
+/**
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+div.tb-user-info {
+ line-height: 1.5;
+ span {
+ text-transform: none;
+ text-align: left;
+ }
+ span.tb-user-display-name {
+ font-size: 0.800rem;
+ font-weight: 300;
+ letter-spacing: 0.008em;
+ }
+ span.tb-user-authority {
+ font-size: 0.800rem;
+ font-weight: 300;
+ letter-spacing: 0.005em;
+ opacity: 0.8;
+ }
+}
+
+md-icon.tb-mini-avatar {
+ margin: auto 8px;
+ font-size: 36px;
+ height: 36px;
+ width: 36px;
+}
ui/src/app/layout/user-menu.tpl.html 28(+28 -0)
diff --git a/ui/src/app/layout/user-menu.tpl.html b/ui/src/app/layout/user-menu.tpl.html
new file mode 100644
index 0000000..3e70334
--- /dev/null
+++ b/ui/src/app/layout/user-menu.tpl.html
@@ -0,0 +1,28 @@
+<section layout="row">
+ <div hide-xs hide-sm ng-show="vm.displayUserInfo" class="tb-user-info" layout="row">
+ <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon>
+ <div layout="column">
+ <span class="tb-user-display-name">{{vm.userDisplayName()}}</span>
+ <span class="tb-user-authority">{{vm.authorityName()}}</span>
+ </div>
+ </div>
+ <md-menu md-position-mode="target-right target">
+ <md-button class="md-icon-button" aria-label="{{ 'home.open-user-menu' | translate }}" ng-click="$mdOpenMenu($event)">
+ <md-icon md-menu-origin aria-label="{{ 'home.open-user-menu' | translate }}" class="material-icons">more_vert</md-icon>
+ </md-button>
+ <md-menu-content width="4">
+ <md-menu-item>
+ <md-button ng-click="vm.openProfile()">
+ <md-icon md-menu-align-target aria-label="{{ 'home.profile' | translate }}" class="material-icons">account_circle</md-icon>
+ <span translate>home.profile</span>
+ </md-button>
+ </md-menu-item>
+ <md-menu-item>
+ <md-button ng-click="vm.logout()">
+ <md-icon md-menu-align-target aria-label="{{ 'home.logout' | translate }}" class="material-icons">exit_to_app</md-icon>
+ <span translate>home.logout</span>
+ </md-button>
+ </md-menu-item>
+ </md-menu-content>
+ </md-menu>
+</section>
ui/src/app/locale/locale.constant.js 4(+3 -1)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 332da30..bf56900 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -632,7 +632,9 @@ export default angular.module('thingsboard.locale', [])
"email-required": "Email is required.",
"first-name": "First Name",
"last-name": "Last Name",
- "description": "Description"
+ "description": "Description",
+ "default-dashboard": "Default dashboard",
+ "always-fullscreen": "Always fullscreen"
},
"value": {
"type": "Value type",
ui/src/app/services/menu.service.js 6(+3 -3)
diff --git a/ui/src/app/services/menu.service.js b/ui/src/app/services/menu.service.js
index 0a0208e..d0d1596 100644
--- a/ui/src/app/services/menu.service.js
+++ b/ui/src/app/services/menu.service.js
@@ -63,7 +63,7 @@ function Menu(userService, $state, $rootScope) {
{
name: 'home.home',
type: 'link',
- state: 'home',
+ state: 'home.links',
icon: 'home'
},
{
@@ -167,7 +167,7 @@ function Menu(userService, $state, $rootScope) {
{
name: 'home.home',
type: 'link',
- state: 'home',
+ state: 'home.links',
icon: 'home'
},
{
@@ -264,7 +264,7 @@ function Menu(userService, $state, $rootScope) {
{
name: 'home.home',
type: 'link',
- state: 'home',
+ state: 'home.links',
icon: 'home'
},
{
ui/src/app/user/user.directive.js 35(+34 -1)
diff --git a/ui/src/app/user/user.directive.js b/ui/src/app/user/user.directive.js
index fb24dec..a05d5ed 100644
--- a/ui/src/app/user/user.directive.js
+++ b/ui/src/app/user/user.directive.js
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+import './user-fieldset.scss';
+
/* eslint-disable import/no-unresolved, import/default */
import userFieldsetTemplate from './user-fieldset.tpl.html';
@@ -20,10 +23,40 @@ import userFieldsetTemplate from './user-fieldset.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
-export default function UserDirective($compile, $templateCache) {
+export default function UserDirective($compile, $templateCache, dashboardService) {
var linker = function (scope, element) {
var template = $templateCache.get(userFieldsetTemplate);
element.html(template);
+
+ scope.isCustomerUser = function() {
+ return scope.user && scope.user.authority === 'CUSTOMER_USER';
+ }
+
+ scope.$watch('user', function(newUser, prevUser) {
+ if (!angular.equals(newUser, prevUser) && newUser) {
+ scope.defaultDashboard = null;
+ if (scope.isCustomerUser() && scope.user.additionalInfo &&
+ scope.user.additionalInfo.defaultDashboardId) {
+ dashboardService.getDashboard(scope.user.additionalInfo.defaultDashboardId).then(
+ function(dashboard) {
+ scope.defaultDashboard = dashboard;
+ }
+ )
+ }
+ }
+ });
+
+ scope.$watch('defaultDashboard', function(newDashboard, prevDashboard) {
+ if (!angular.equals(newDashboard, prevDashboard)) {
+ if (scope.isCustomerUser()) {
+ if (!scope.user.additionalInfo) {
+ scope.user.additionalInfo = {};
+ }
+ scope.user.additionalInfo.defaultDashboardId = newDashboard ? newDashboard.id.id : null;
+ }
+ }
+ });
+
$compile(element.contents())(scope);
}
return {
ui/src/app/user/user-fieldset.scss 31(+31 -0)
diff --git a/ui/src/app/user/user-fieldset.scss b/ui/src/app/user/user-fieldset.scss
new file mode 100644
index 0000000..ff02a0c
--- /dev/null
+++ b/ui/src/app/user/user-fieldset.scss
@@ -0,0 +1,31 @@
+/**
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '../../scss/constants';
+
+.tb-default-dashboard {
+ .tb-default-dashboard-label {
+ padding-bottom: 8px;
+ }
+ tb-dashboard-select {
+ @media (min-width: $layout-breakpoint-gt-sm) {
+ padding-right: 12px;
+ }
+ @media (max-width: $layout-breakpoint-gt-sm) {
+ padding-bottom: 12px;
+ }
+ }
+}
\ No newline at end of file
ui/src/app/user/user-fieldset.tpl.html 15(+15 -0)
diff --git a/ui/src/app/user/user-fieldset.tpl.html b/ui/src/app/user/user-fieldset.tpl.html
index e6b48d4..8812798 100644
--- a/ui/src/app/user/user-fieldset.tpl.html
+++ b/ui/src/app/user/user-fieldset.tpl.html
@@ -43,5 +43,20 @@
<label translate>user.description</label>
<textarea ng-model="user.additionalInfo.description" rows="2"></textarea>
</md-input-container>
+ <section class="tb-default-dashboard" flex layout="column"ng-show="isCustomerUser()">
+ <span class="tb-default-dashboard-label" ng-class="{'tb-disabled-label': loading || !isEdit}" translate>user.default-dashboard</span>
+ <section flex layout="column" layout-gt-sm="row">
+ <tb-dashboard-select flex
+ the-form="theForm"
+ ng-model="defaultDashboard"
+ dashboards-scope="customer"
+ customer-id="user.customerId.id"
+ select-first-dashboard="false">
+ </tb-dashboard-select>
+ <md-checkbox ng-disabled="loading || !isEdit" flex aria-label="{{ 'user.always-fullscreen' | translate }}"
+ ng-model="user.additionalInfo.defaultDashboardFullscreen">{{ 'user.always-fullscreen' | translate }}
+ </md-checkbox>
+ </section>
+ </section>
</fieldset>
</md-content>