Added luna template and deps
Change-Id: Idd3dcdee3a377a75733c333d4a754632111e17ee
diff --git a/src/app/core/header/header.html b/src/app/core/header/header.html
index 8359ab3..db25904 100644
--- a/src/app/core/header/header.html
+++ b/src/app/core/header/header.html
@@ -1,19 +1,55 @@
-<header class="header">
- <p class="header-title">
- <a href="#/" target="_blank">
- {{vm.title}}
- </a>
- </p>
- <p class="header-date notification">
- <i ng-if="vm.newNotifications.length > 0" class="badge"></i>
- <i class="fa fa-bell" ng-click="vm.showNotification = !vm.showNotification"></i>
- <div class="notification-panel" ng-show="vm.showNotification">
- <ul>
- <li ng-repeat="n in vm.notifications track by $index" ng-click="vm.viewNotification(n)" ng-class="{viewed: n.viewed}">
- <b>{{n.model}}</b><br>
- <i>{{n.msg.object.name}} status is {{n.msg.object.backend_status}}</i>
+<!--<header class="header">-->
+ <!--<p class="header-title">-->
+ <!--<a href="#/" target="_blank">-->
+ <!--{{vm.title}}-->
+ <!--</a>-->
+ <!--</p>-->
+ <!--<p class="header-date notification">-->
+ <!--<i ng-if="vm.newNotifications.length > 0" class="badge"></i>-->
+ <!--<i class="fa fa-bell" ng-click="vm.showNotification = !vm.showNotification"></i>-->
+ <!--<div class="notification-panel" ng-show="vm.showNotification">-->
+ <!--<ul>-->
+ <!--<li ng-repeat="n in vm.notifications track by $index" ng-click="vm.viewNotification(n)" ng-class="{viewed: n.viewed}">-->
+ <!--<b>{{n.model}}</b><br>-->
+ <!--<i>{{n.msg.object.name}} status is {{n.msg.object.backend_status}}</i>-->
+ <!--</li>-->
+ <!--</ul>-->
+ <!--</div>-->
+ <!--</p>-->
+<!--</header>-->
+
+
+<!-- Header -->
+<nav class="navbar navbar-default navbar-fixed-top">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <div id="mobile-menu">
+ <minimaliza-menu></minimaliza-menu>
+ </div>
+ <a class="navbar-brand" href="#/">
+ <em class="brand-title">{{vm.title}}</em>
+ <span>v.1.2</span>
+ </a>
+ </div>
+ <div id="navbar" class="navbar-collapse collapse">
+ <minimaliza-menu></minimaliza-menu>
+ <!--<form class="navbar-form navbar-left">-->
+ <!--<input type="text" class="form-control" placeholder="Search data for analysis" style="width: 175px">-->
+ <!--</form>-->
+ <ul class="nav navbar-nav navbar-right">
+ <!--<li class="dropdown">-->
+ <!--<a ui-sref="main.versions">-->
+ <!--<i class="fa fa-bell"></i>-->
+ <!--<span ng-if="vm.newNotifications.length > 0" class="label label-warning pull-right">{{vm.newNotifications.length}}</span>-->
+ <!--</a>-->
+ <!--</li>-->
+ <li class=" profil-link">
+ <a ui-sref="commonviews.login">
+ <span class="profile-address">luna@company.io</span>
+ <img src="../../images/profile.jpg" class="img-circle" alt="">
+ </a>
</li>
</ul>
</div>
- </p>
-</header>
+ </div>
+</nav>
\ No newline at end of file
diff --git a/src/app/core/header/header.scss b/src/app/core/header/header.scss
index 2ff7ce1..8a1664f 100644
--- a/src/app/core/header/header.scss
+++ b/src/app/core/header/header.scss
@@ -1,43 +1,3 @@
-xos-header {
- .badge {
- display: block;
- width: 3px;
- height: 3px;
- border-radius: 50%;
- border: 4px solid red;
- background: transparent;
- position: absolute;
- right: 15px;
- top: 18px;
- }
-
- .fa {
- cursor: pointer;
- }
-
- .notification-panel {
- position: absolute;
- background: darken(grey, 5);
- right: 10px;
- top: 60px;
- border: 1px solid darken(grey, 35);
- max-height: 200px;
- overflow-y: scroll;
-
- ul {
- margin: 0;
- padding: 0;
- list-style: none;
-
- li {
- padding: 10px;
- border-bottom: 1px solid darken(grey, 35);
- color: #fff;
-
- &.viewed {
- background: darken(grey, 20);
- }
- }
- }
- }
+#toast-container [toast]:not(:first-child) {
+ margin-top: 10px !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 1f2c1aa..8662719 100644
--- a/src/app/core/header/header.spec.ts
+++ b/src/app/core/header/header.spec.ts
@@ -18,14 +18,25 @@
return events.asObservable();
};
};
-const sampleNotification = {
+
+interface ImockToastr {
+ info(msg: string, title: string): void;
+}
+
+const MockToastr: ImockToastr = {
+ info: jasmine.createSpy('info')
+};
+
+const MockToastrConfig = {};
+
+const infoNotification = {
model: 'TestModel',
msg: {
changed_fields: ['backend_status'],
pk: 1,
object: {
name: 'TestName',
- backend_status: 'Test Status'
+ backend_status: '1 - Test Status'
}
}
};
@@ -35,7 +46,9 @@
angular
.module('xosHeader', ['app/core/header/header.html'])
.component('xosHeader', xosHeader)
- .service('SynchronizerStore', MockStore);
+ .service('SynchronizerStore', MockStore)
+ .value('toastr', MockToastr)
+ .value('toastrConfig', MockToastrConfig);
angular.mock.module('xosHeader');
});
@@ -51,57 +64,26 @@
}));
it('should render the appropriate title', () => {
- const header = element.find('a');
- expect(header.html().trim()).toEqual(StyleConfig.projectName);
-
- const badge = $('i.badge', element);
- expect(badge.length).toBe(0);
+ const header = $('a.navbar-brand .brand-title', element).text();
+ expect(header.trim()).toEqual(StyleConfig.projectName);
});
- it('should display a badge if there are unread notifications', () => {
- sendEvent(sampleNotification);
- scope.$digest();
-
- const badge = $('i.badge', element);
- expect(badge.length).toBe(1);
+ it('should configure toastr', () => {
+ expect(MockToastrConfig).toEqual({
+ newestOnTop: false,
+ positionClass: 'toast-top-right',
+ preventDuplicates: false,
+ preventOpenDuplicates: false,
+ progressBar: true,
+ });
});
- it('should not display a badge if there are notifications have been read', () => {
- sendEvent(angular.extend({viewed: true}, sampleNotification));
+ it('should display a toastr for a new notification', () => {
+ sendEvent(infoNotification);
scope.$digest();
- const badge = $('i.badge', element);
- expect(badge.length).toBe(0);
+ expect(MockToastr.info).toHaveBeenCalledWith('Synchronization started for: TestName', 'TestModel');
});
- it('should display a list of notifications', () => {
- isolatedScope.showNotification = true;
- sendEvent(angular.extend({viewed: true}, sampleNotification));
- sendEvent(angular.extend({viewed: false}, sampleNotification));
- scope.$digest();
-
- const badge = $('i.badge', element);
- expect(badge.length).toBe(1);
- const notificationPanel = $('.notification-panel', element);
- expect(notificationPanel.length).toBe(1);
-
- expect($('.notification-panel li', element).length).toBe(2);
- });
-
- it('should add the viewed class to an readed notification', () => {
- isolatedScope.showNotification = true;
- sendEvent(angular.extend({viewed: true}, sampleNotification));
- scope.$digest();
- expect($('.notification-panel li:first-child', element)).toHaveClass('viewed');
- scope.$digest();
- });
-
- it('should not add the viewed class to an unread notification', () => {
- isolatedScope.showNotification = true;
- sendEvent(angular.extend({viewed: false}, sampleNotification));
- scope.$digest();
- expect($('.notification-panel li:first-child', element)).not.toHaveClass('viewed');
- scope.$digest();
- });
-
+ // TODO test error and success toaster call
});
diff --git a/src/app/core/header/header.ts b/src/app/core/header/header.ts
index 20fbc3c..6e057bc 100644
--- a/src/app/core/header/header.ts
+++ b/src/app/core/header/header.ts
@@ -8,21 +8,54 @@
}
class HeaderController {
- static $inject = ['$scope', 'SynchronizerStore'];
+ static $inject = ['$scope', 'SynchronizerStore', 'toastr', 'toastrConfig'];
public title: string;
public notifications: INotification[] = [];
public newNotifications: INotification[] = [];
constructor(
private $scope: angular.IScope,
- private syncStore: IStoreService
+ private syncStore: IStoreService,
+ private toastr: ng.toastr.IToastrService,
+ private toastrConfig: ng.toastr.IToastrConfig
) {
+
+ angular.extend(this.toastrConfig, {
+ newestOnTop: false,
+ positionClass: 'toast-top-right',
+ preventDuplicates: false,
+ preventOpenDuplicates: false,
+ progressBar: true,
+ // autoDismiss: false,
+ // closeButton: false,
+ // timeOut: 0,
+ // tapToDismiss: false
+ });
+
this.title = StyleConfig.projectName;
this.syncStore.query()
.subscribe(
(event: IWSEvent) => {
$scope.$evalAsync(() => {
+ let toastrMsg: string;
+ let toastrLevel: string;
+ if (event.msg.object.backend_status.indexOf('1') > -1) {
+ toastrMsg = 'Synchronization started for:';
+ toastrLevel = 'info';
+ }
+ else if (event.msg.object.backend_status.indexOf('0') > -1) {
+ toastrMsg = 'Synchronization succedeed for:';
+ toastrLevel = 'success';
+ }
+ else if (event.msg.object.backend_status.indexOf('2') > -1) {
+ toastrMsg = 'Synchronization failed for:';
+ toastrLevel = 'error';
+ }
+
+ if (toastrLevel && toastrMsg) {
+ this.toastr[toastrLevel](`${toastrMsg} ${event.msg.object.name}`, event.model);
+ }
this.notifications.unshift(event);
this.newNotifications = this.getNewNotifications(this.notifications);
});
@@ -30,6 +63,7 @@
);
}
+ // TODO display a list of notification in the template
public viewNotification = (notification: INotification) => {
notification.viewed = true;
this.newNotifications = this.getNewNotifications(this.notifications);
diff --git a/src/app/core/index.ts b/src/app/core/index.ts
index a89edf5..a9aa9a6 100644
--- a/src/app/core/index.ts
+++ b/src/app/core/index.ts
@@ -12,11 +12,12 @@
import {XosFormHelpers} from './form/form-helpers';
import {xosForm} from './form/form';
import {xosField} from './field/field';
+import 'angular-toastr';
export const xosCore = 'xosCore';
angular
- .module('xosCore', ['ui.router'])
+ .module('xosCore', ['ui.router', 'toastr'])
.config(routesConfig)
.provider('RuntimeStates', RuntimeStates)
.service('NavigationService', NavigationService)
diff --git a/src/app/core/login/login.html b/src/app/core/login/login.html
index f4a0724..710822a 100644
--- a/src/app/core/login/login.html
+++ b/src/app/core/login/login.html
@@ -1,5 +1,46 @@
-<form name="login">
- <input type="text" name="username" ng-model="username" required>
- <input type="text" name="password" ng-model="password" required>
- <button type="button" ng-click="vm.login(username, password)">Login</button>
-</form>
+<!--<form name="login">-->
+ <!--<input type="text" name="username" ng-model="username" required>-->
+ <!--<input type="text" name="password" ng-model="password" required>-->
+ <!--<button type="button" ng-click="vm.login(username, password)">Login</button>-->
+<!--</form>-->
+<!-- Main content-->
+<section class="content">
+
+ <div class="container-center animated slideInDown">
+
+ <div class="view-header">
+ <div class="header-icon">
+ <i class="pe page-header-icon pe-7s-unlock"></i>
+ </div>
+ <div class="header-title">
+ <h3>Login</h3>
+ <small>
+ Please enter your credentials to login.
+ </small>
+ </div>
+ </div>
+
+ <div class="panel panel-filled">
+ <div class="panel-body">
+ <form id="loginForm" ng-submit="vm.login(username, password)" novalidate>
+ <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>
+ </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>
+ </div>
+ <div>
+ <button ng-click="vm.login(username, password)" class="btn btn-accent">Login</button>
+ <!--<a class="btn btn-default" href="register.html">Register</a>-->
+ </div>
+ </form>
+ </div>
+ </div>
+
+ </div>
+</section>
+<!-- End main content-->
\ No newline at end of file
diff --git a/src/app/core/login/login.ts b/src/app/core/login/login.ts
index e5881dd..ca500dc 100644
--- a/src/app/core/login/login.ts
+++ b/src/app/core/login/login.ts
@@ -11,6 +11,7 @@
}
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 8420839..fe96460 100644
--- a/src/app/core/nav/nav.html
+++ b/src/app/core/nav/nav.html
@@ -1,23 +1,35 @@
-<div class="nav">
- <ul>
- <li
- ng-repeat="route in vm.routes track by $index"
- ui-sref-active="active"
- ng-class="vm.isRouteActive(route)">
- <a ng-if="route.state" ui-sref="{{route.state}}" ng-click="vm.activateRoute(route)">
- <i ng-if="route.children" class="fa fa-chevron-right"></i>
- {{route.label}}
- </a>
- <a ng-if="route.url" href="#/{{route.url}}" ng-click="vm.activateRoute(route)">
- <i ng-if="route.children" class="fa fa-chevron-right"></i>
- {{route.label}}
- </a>
- <ul class="child-routes" ng-if="route.children" ng-class="{opened: route.opened}">
- <li ng-repeat="childRoute in route.children | orderBy:'label'" ui-sref-active="active">
- <a ng-if="childRoute.state" ui-sref="{{childRoute.state}}">{{childRoute.label}}</a>
- <a ng-if="childRoute.url" href="#/{{childRoute.url}}">{{childRoute.label}}</a>
- </li>
- </ul>
- </li>
- </ul>
-</div>
+<!-- Navigation -->
+<aside class="navigation">
+ <!-- Navigation-->
+ <nav>
+ <ul class="nav luna-nav">
+ <!--<li class="nav-category">-->
+ <!--Main-->
+ <!--</li>-->
+ <li
+ ng-repeat="route in vm.routes track by $index"
+ ui-sref-active="active">
+ <a ng-if="route.state && !route.children" ui-sref="{{route.state}}" ng-click="vm.activateRoute(route)">
+ {{route.label}}
+ </a>
+ <a ng-if="route.state && route.children" ng-click="vm.activateRoute(route)">
+ {{route.label}}<span class="sub-nav-icon"> <i class="stroke-arrow"></i> </span>
+ </a>
+ <ul class="nav nav-second" uib-collapse="vm.isSelected(route.state, vm.navSelected)">
+ <li ng-repeat="childRoute in route.children | orderBy:'label'" ui-sref-active="active">
+ <a ui-sref="{{childRoute.state}}"> {{childRoute.label}}</a>
+ </li>
+ </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>
+ </li>
+ </ul>
+ </nav>
+ <!-- End navigation-->
+</aside>
\ No newline at end of file
diff --git a/src/app/core/nav/nav.scss b/src/app/core/nav/nav.scss
index dbe60d7..e69de29 100644
--- a/src/app/core/nav/nav.scss
+++ b/src/app/core/nav/nav.scss
@@ -1,58 +0,0 @@
-xos-nav {
- display: flex;
- flex: 1;
- flex-direction: column;
- flex-basis: 15%;
- background: darken(grey, 10);
- overflow-y: scroll;
-
- ul {
- list-style: none;
- padding: 0;
- margin: 0;
- background: grey;
-
- > li {
- display: flex;
- flex-direction: column;
- border-bottom: 1px solid darken(grey, 20);
-
- &.active {
- background: darken(grey, 10);
-
- > a {
- color: #5aadbb;
- }
- }
-
- &:hover {
- background: darken(grey, 10);
- }
-
- > a {
- padding: 10px 20px;
- cursor: pointer;
- }
-
- // child router
- > ul {
- height: 0;
- overflow: hidden;
- transition: .5s all;
-
- > li {
- padding-left: 20px;
- background: darken(grey, 15);
-
- &:hover, &.active {
- background: darken(grey, 20);
- }
- }
- }
-
- > ul.opened {
- height: auto;
- }
- }
- }
-}
diff --git a/src/app/core/nav/nav.spec.ts b/src/app/core/nav/nav.spec.ts
index fbed8ea..6a70f4c 100644
--- a/src/app/core/nav/nav.spec.ts
+++ b/src/app/core/nav/nav.spec.ts
@@ -39,7 +39,7 @@
}));
it('should render a list of routes', () => {
- const routes = $('.nav ul li', element);
+ const routes = $('.nav li:not(.nav-info)', element);
expect(routes.length).toBe(2);
});
@@ -51,7 +51,7 @@
]}
];
scope.$apply();
- const childRouteContainer = $('.child-routes', element);
+ const childRouteContainer = $('.nav-second li', element);
expect(childRouteContainer.length).toBe(1);
});
});
diff --git a/src/app/core/nav/nav.ts b/src/app/core/nav/nav.ts
index 6c6537e..edaeb24 100644
--- a/src/app/core/nav/nav.ts
+++ b/src/app/core/nav/nav.ts
@@ -1,9 +1,12 @@
import './nav.scss';
import {IXosNavigationService, IXosNavigationRoute} from '../services/navigation';
+import {StyleConfig} from '../../config/style.config';
class NavCtrl {
static $inject = ['$scope', '$state', 'NavigationService'];
public routes: IXosNavigationRoute[];
+ public navSelected: string;
+ public appName: string;
constructor(
private $scope: ng.IScope,
@@ -18,14 +21,38 @@
this.$scope.$watch(() => this.navigationService.query(), (routes) => {
this.routes = routes;
});
- }
-
- isRouteActive(route: IXosNavigationRoute) {
- return this.$state.current.url === route.url ? 'active' : '';
+ this.appName = StyleConfig.projectName;
}
activateRoute(route: IXosNavigationRoute) {
- route.opened = !route.opened;
+ this.navSelected = route.state;
+ }
+
+ includes(state: string): boolean {
+ return this.$state.includes(state);
+ }
+
+ isSelected(navId: string, navSelected: string) {
+
+ // TODO activate only one state
+
+ const activeRoute = this.$state.current.name;
+ const separateRoutes = activeRoute.split('.');
+
+ if (!navSelected) {
+ navSelected = separateRoutes[1];
+ }
+
+ if (navId === navSelected) {
+ return false;
+ }
+ else if (this.$state.current.name.indexOf(navId) === -1 && navId === navSelected ) {
+ return false;
+ }
+ else {
+ return true;
+ }
+
}
}
diff --git a/src/app/core/routes.ts b/src/app/core/routes.ts
index 5f37713..7bacb85 100644
--- a/src/app/core/routes.ts
+++ b/src/app/core/routes.ts
@@ -5,6 +5,10 @@
$stateProvider
.state('login', {
url: '/login',
- component: 'xosLogin'
+ component: 'xosLogin',
+ data: {
+ specialClass: 'blank'
+ }
});
}
+
diff --git a/src/app/core/table/table.ts b/src/app/core/table/table.ts
index 77067fa..dba740e 100644
--- a/src/app/core/table/table.ts
+++ b/src/app/core/table/table.ts
@@ -37,10 +37,14 @@
public columns: any[];
public orderBy: string;
public reverse: boolean;
+ public classes: string;
private config: IXosTableCfg;
$onInit() {
+
+ this.classes = 'table table-striped'; // table-bordered
+
if (!this.config) {
throw new Error('[xosTable] Please provide a configuration via the "config" attribute');
}