Added logout
Change-Id: If09690e089976244ded58a27b1f35a3a850ae2d1
diff --git a/src/app/core/header/header.html b/src/app/core/header/header.html
index db25904..0a90822 100644
--- a/src/app/core/header/header.html
+++ b/src/app/core/header/header.html
@@ -27,8 +27,8 @@
<minimaliza-menu></minimaliza-menu>
</div>
<a class="navbar-brand" href="#/">
- <em class="brand-title">{{vm.title}}</em>
- <span>v.1.2</span>
+ <img class="img-responsive" ng-src="{{vm.getLogo()}}" alt="">
+ <span>v.{{vm.version}}</span>
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
@@ -45,7 +45,7 @@
<!--</li>-->
<li class=" profil-link">
<a ui-sref="commonviews.login">
- <span class="profile-address">luna@company.io</span>
+ <span class="profile-address">{{vm.userEmail}}</span>
<img src="../../images/profile.jpg" class="img-circle" alt="">
</a>
</li>
diff --git a/src/app/core/header/header.scss b/src/app/core/header/header.scss
index 8a1664f..a1be115 100644
--- a/src/app/core/header/header.scss
+++ b/src/app/core/header/header.scss
@@ -1,3 +1,21 @@
#toast-container [toast]:not(:first-child) {
margin-top: 10px !important;
+}
+
+xos-header {
+ .navbar-brand {
+ padding: 10px 30px !important;
+ position: relative;
+ background: #24262d !important;
+ span {
+ position: absolute;
+ right: 30px;
+ bottom: 0;
+ color: #24262d;
+ }
+ }
+
+ .navbar-default {
+ background: #2a2d35 !important;
+ }
}
\ No newline at end of file
diff --git a/src/app/core/header/header.spec.ts b/src/app/core/header/header.spec.ts
index c8dffe7..c115a4e 100644
--- a/src/app/core/header/header.spec.ts
+++ b/src/app/core/header/header.spec.ts
@@ -5,7 +5,6 @@
import * as angular from 'angular';
import 'angular-mocks';
import {xosHeader, INotification} from './header';
-import {StyleConfig} from '../../config/style.config';
import {Subject} from 'rxjs';
let element, scope: angular.IRootScopeService, compile: ng.ICompileService, isolatedScope;
@@ -19,14 +18,16 @@
};
};
-interface ImockToastr {
- info(msg: string, title: string): void;
-}
-
-const MockToastr: ImockToastr = {
+const MockToastr = {
info: jasmine.createSpy('info')
};
+const MockAuth = {
+ getUser: () => {
+ return {email: 'test@xos.us'};
+ }
+};
+
const MockToastrConfig = {};
const infoNotification = {
@@ -36,7 +37,7 @@
pk: 1,
object: {
name: 'TestName',
- backend_status: '1 - Test Status'
+ backend_status: '0 - In Progress'
}
}
};
@@ -48,7 +49,8 @@
.component('xosHeader', xosHeader)
.service('SynchronizerStore', MockStore)
.value('toastr', MockToastr)
- .value('toastrConfig', MockToastrConfig);
+ .value('toastrConfig', MockToastrConfig)
+ .value('AuthService', MockAuth);
angular.mock.module('xosHeader');
});
@@ -63,13 +65,14 @@
isolatedScope.notifications = [];
}));
- it('should render the appropriate title', () => {
- const header = $('a.navbar-brand .brand-title', element).text();
- expect(header.trim()).toEqual(StyleConfig.projectName);
+ it('should render the appropriate logo', () => {
+ const header = $('a.navbar-brand img', element).attr('src');
+ // webpack convert img to base64, how to test?
+ expect(header.trim()).not.toBeNull();
});
- it('should set the appropriate favicon', () => {
- console.log($('#favicon').attr('href'));
+ it('should print user email', () => {
+ expect($('.profile-address', element).text()).toBe('test@xos.us');
});
it('should configure toastr', () => {
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index 6e057bc..efaa385 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -2,24 +2,27 @@
import {StyleConfig} from '../../config/style.config';
import {IWSEvent} from '../../datasources/websocket/global';
import {IStoreService} from '../../datasources/stores/synchronizer.store';
+import {IXosAuthService} from '../../datasources/rest/auth.rest';
export interface INotification extends IWSEvent {
viewed?: boolean;
}
class HeaderController {
- static $inject = ['$scope', 'SynchronizerStore', 'toastr', 'toastrConfig'];
- public title: string;
+ static $inject = ['$scope', 'AuthService', 'SynchronizerStore', 'toastr', 'toastrConfig'];
public notifications: INotification[] = [];
public newNotifications: INotification[] = [];
+ public version: string;
+ public userEmail: string;
constructor(
private $scope: angular.IScope,
+ private authService: IXosAuthService,
private syncStore: IStoreService,
private toastr: ng.toastr.IToastrService,
private toastrConfig: ng.toastr.IToastrConfig
) {
-
+ this.version = require('../../../../package.json').version;
angular.extend(this.toastrConfig, {
newestOnTop: false,
positionClass: 'toast-top-right',
@@ -32,7 +35,7 @@
// tapToDismiss: false
});
- this.title = StyleConfig.projectName;
+ this.userEmail = this.authService.getUser().email;
this.syncStore.query()
.subscribe(
@@ -40,11 +43,11 @@
$scope.$evalAsync(() => {
let toastrMsg: string;
let toastrLevel: string;
- if (event.msg.object.backend_status.indexOf('1') > -1) {
+ if (event.msg.object.backend_status.indexOf('0') > -1) {
toastrMsg = 'Synchronization started for:';
toastrLevel = 'info';
}
- else if (event.msg.object.backend_status.indexOf('0') > -1) {
+ else if (event.msg.object.backend_status.indexOf('1') > -1) {
toastrMsg = 'Synchronization succedeed for:';
toastrLevel = 'success';
}
@@ -56,24 +59,28 @@
if (toastrLevel && toastrMsg) {
this.toastr[toastrLevel](`${toastrMsg} ${event.msg.object.name}`, event.model);
}
- this.notifications.unshift(event);
- this.newNotifications = this.getNewNotifications(this.notifications);
+ // this.notifications.unshift(event);
+ // this.newNotifications = this.getNewNotifications(this.notifications);
});
}
);
}
- // TODO display a list of notification in the template
- public viewNotification = (notification: INotification) => {
- notification.viewed = true;
- this.newNotifications = this.getNewNotifications(this.notifications);
- };
+ public getLogo(): string {
+ return require(`../../images/brand/${StyleConfig.logo}`);
+ }
- private getNewNotifications = (notifications: INotification[]) => {
- return this.notifications.filter((n: INotification) => {
- return !n.viewed;
- });
- };
+ // TODO display a list of notification in the template (if it make sense)
+ // public viewNotification = (notification: INotification) => {
+ // notification.viewed = true;
+ // this.newNotifications = this.getNewNotifications(this.notifications);
+ // };
+ //
+ // private getNewNotifications = (notifications: INotification[]) => {
+ // return this.notifications.filter((n: INotification) => {
+ // return !n.viewed;
+ // });
+ // };
}
export const xosHeader: angular.IComponentOptions = {
diff --git a/src/app/core/login/login.html b/src/app/core/login/login.html
index 6f23959..4fa78dc 100644
--- a/src/app/core/login/login.html
+++ b/src/app/core/login/login.html
@@ -25,12 +25,12 @@
<div class="form-group">
<label class="control-label" for="username">Username</label>
<input type="text" ng-model="username" placeholder="example@gmail.com" title="Please enter you username" required="" value="" name="username" id="username" class="form-control">
- <span class="help-block small">Your unique username to app</span>
+ <!--<span class="help-block small">Your unique username to app</span>-->
</div>
<div class="form-group">
<label class="control-label" for="password">Password</label>
<input type="password" ng-model="password" title="Please enter your password" placeholder="******" required="" value="" name="password" id="password" class="form-control">
- <span class="help-block small">Your strong password</span>
+ <!--<span class="help-block small">Your strong password</span>-->
</div>
<div>
<button ng-click="vm.login(username, password)" class="btn btn-accent">Login</button>
diff --git a/src/app/core/login/login.scss b/src/app/core/login/login.scss
index 88a907a..8fe8a57 100644
--- a/src/app/core/login/login.scss
+++ b/src/app/core/login/login.scss
@@ -2,6 +2,8 @@
.content {
background-repeat: no-repeat;
background-size: cover;
+ background-position: center;
+ min-height: 100%;
}
.container-center {
diff --git a/src/app/core/login/login.ts b/src/app/core/login/login.ts
index 11642f1..334ad08 100644
--- a/src/app/core/login/login.ts
+++ b/src/app/core/login/login.ts
@@ -19,7 +19,6 @@
}
public login(username: string, password: string) {
- console.log(username, password);
this.authService.login({
username: username,
password: password
diff --git a/src/app/core/nav/nav.html b/src/app/core/nav/nav.html
index fe96460..37d2f76 100644
--- a/src/app/core/nav/nav.html
+++ b/src/app/core/nav/nav.html
@@ -22,11 +22,26 @@
</ul>
</li>
<li class="nav-info">
- <i class="pe pe-7s-shield text-accent"></i>
-
- <div class="m-t-xs">
- <span class="c-white">{{vm.appName}}</span>
- monitoring and administration for networks applications.
+ <div class="row">
+ <div class="col-sm-4">
+ <i class="pe pe-7s-shield text-accent"></i>
+ </div>
+ <div class="col-sm-8">
+ <h4 class="c-white">{{vm.appName}}</h4>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-xs-12">
+ <span class="c-white">{{vm.payoff}}</span>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-sm-4">
+ <i class="pe pe-7s-lock text-accent"></i>
+ </div>
+ <div class="col-sm-8">
+ <a ng-click="vm.logout()" class="btn btn-accent btn-block btn-logout">Logout</a>
+ </div>
</div>
</li>
</ul>
diff --git a/src/app/core/nav/nav.scss b/src/app/core/nav/nav.scss
index e69de29..7646cd9 100644
--- a/src/app/core/nav/nav.scss
+++ b/src/app/core/nav/nav.scss
@@ -0,0 +1,7 @@
+xos-nav {
+ .nav-info {
+ .row + .row:last-child {
+ margin-top: 20px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/core/nav/nav.spec.ts b/src/app/core/nav/nav.spec.ts
index 6a70f4c..3c18e4d 100644
--- a/src/app/core/nav/nav.spec.ts
+++ b/src/app/core/nav/nav.spec.ts
@@ -18,12 +18,17 @@
this.query = () => baseRoutes;
};
+const AuthMock = {
+ logout: jasmine.createSpy('logout')
+};
+
describe('Nav component', () => {
beforeEach(() => {
angular
.module('xosNav', ['app/core/nav/nav.html', 'ui.router'])
.component('xosNav', xosNav)
- .service('NavigationService', NavigationService);
+ .service('NavigationService', NavigationService)
+ .value('AuthService', AuthMock);
angular.mock.module('xosNav');
});
@@ -54,4 +59,13 @@
const childRouteContainer = $('.nav-second li', element);
expect(childRouteContainer.length).toBe(1);
});
+
+ it('should call the logout method', () => {
+ // NOTE upgrade to test the ng-click binding
+ // const btn = $(element).find('.nav-info .btn-block');
+ // btn.click();
+ // scope.$digest();
+ isolatedScope.vm.logout();
+ expect(AuthMock.logout).toHaveBeenCalled();
+ });
});
diff --git a/src/app/core/nav/nav.ts b/src/app/core/nav/nav.ts
index edaeb24..43f62b3 100644
--- a/src/app/core/nav/nav.ts
+++ b/src/app/core/nav/nav.ts
@@ -1,17 +1,20 @@
import './nav.scss';
import {IXosNavigationService, IXosNavigationRoute} from '../services/navigation';
import {StyleConfig} from '../../config/style.config';
+import {IXosAuthService} from '../../datasources/rest/auth.rest';
class NavCtrl {
- static $inject = ['$scope', '$state', 'NavigationService'];
+ static $inject = ['$scope', '$state', 'NavigationService', 'AuthService'];
public routes: IXosNavigationRoute[];
public navSelected: string;
public appName: string;
+ public payoff: string;
constructor(
private $scope: ng.IScope,
private $state: angular.ui.IStateService,
- private navigationService: IXosNavigationService
+ private navigationService: IXosNavigationService,
+ private authService: IXosAuthService
) {
// NOTE we'll need to have:
// - Base routes (defined from configuration based on BRAND)
@@ -22,6 +25,7 @@
this.routes = routes;
});
this.appName = StyleConfig.projectName;
+ this.payoff = StyleConfig.payoff;
}
activateRoute(route: IXosNavigationRoute) {
@@ -52,7 +56,10 @@
else {
return true;
}
+ }
+ logout() {
+ this.authService.logout();
}
}
diff --git a/src/app/core/services/helpers/config.helpers.ts b/src/app/core/services/helpers/config.helpers.ts
index 9d0c191..f9b76f0 100644
--- a/src/app/core/services/helpers/config.helpers.ts
+++ b/src/app/core/services/helpers/config.helpers.ts
@@ -74,7 +74,7 @@
prop: f.name
};
- if (f.name === 'id') {
+ if (f.name === 'id' || f.name === 'name') {
// NOTE can we find a better method to generalize?
col.link = item => `#/core${baseUrl.replace(':id?', item.id)}`;
}
@@ -93,6 +93,7 @@
}
};
}
+
return col;
})
.filter(v => angular.isDefined(v));
diff --git a/src/app/core/services/navigation.ts b/src/app/core/services/navigation.ts
index c840878..d184fc2 100644
--- a/src/app/core/services/navigation.ts
+++ b/src/app/core/services/navigation.ts
@@ -23,16 +23,20 @@
constructor() {
const defaultRoutes = [
{
+ label: 'Home',
+ state: 'xos.dashboard'
+ },
+ {
label: 'Core',
state: 'xos.core'
},
- {
- label: 'Home',
- state: 'xos.dashboard'
- }
];
// adding configuration defined routes
- this.routes = StyleConfig.routes.concat(defaultRoutes).reverse();
+ // this.routes = StyleConfig.routes.concat(defaultRoutes).reverse();
+ this.routes = defaultRoutes;
+ StyleConfig.routes.forEach(r => {
+ this.add(r);
+ });
}
query() {