From 280daa7f3f858ecfef9c91ffd5dea1007f021048 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Sun, 19 Mar 2017 11:29:37 +0000
Subject: [PATCH] #3527 fix - Added applications and some minor refactoring

---
 securis/src/main/webapp/src/app/common/utils.ts                         |   50 +
 securis/src/main/webapp/src/app/forms/base.ts                           |   59 +
 securis/src/main/webapp/src/app/listing/application.list.component.ts   |   89 ++
 securis/src/main/webapp/src/app/forms/login.form.html                   |    0 
 securis/src/main/webapp/src/app/listing/pack.list.component.ts          |  122 ++++
 securis/src/main/webapp/src/app/common/i18n.ts                          |   25 
 securis/src/main/webapp/src/app/menu.component.ts                       |   14 
 securis/src/main/webapp/src/app/listing/base.ts                         |   83 ++
 securis/src/main/webapp/src/app/forms/application.form.html             |  152 +++++
 securis/src/main/webapp/src/app/listing/pack.list.component.html        |    4 
 securis/src/main/webapp/src/app/forms/pack.form.component.ts            |   40 
 securis/src/main/webapp/src/app/menu.component.html                     |   27 
 securis/src/main/webapp/src/app/forms/license.form.component.ts         |   91 ++
 securis/src/main/webapp/src/app/listing/license.list.component.html     |   16 
 securis/src/main/webapp/src/app/forms/license.form.html                 |  193 ++++--
 securis/src/main/webapp/src/app/forms/application.form.component.ts     |   64 ++
 securis/src/main/webapp/src/app/listing/license.list.component.ts       |  117 +++
 securis/src/main/webapp/src/app/app.routes.ts                           |   23 
 securis/src/main/webapp/src/app/common/error.checker.ts                 |    1 
 securis/src/main/webapp/src/app/forms/login.form.component.ts           |    4 
 /dev/null                                                               |  179 -----
 securis/src/main/webapp/src/app/listing/application.list.component.html |   37 +
 securis/src/main/webapp/src/app/resources/packs.ts                      |    5 
 securis/src/main/webapp/src/app/app.module.ts                           |   20 
 securis/src/main/webapp/src/app/user.service.ts                         |    5 
 securis/src/main/webapp/src/app/forms/pack.form.html                    |  345 +++++------
 securis/src/main/webapp/assets/securis.css                              |   12 
 securis/src/main/webapp/src/lang/messages_en.json                       |    7 
 28 files changed, 1,252 insertions(+), 532 deletions(-)

diff --git a/securis/src/main/webapp/assets/securis.css b/securis/src/main/webapp/assets/securis.css
index 80fe531..97c1372 100644
--- a/securis/src/main/webapp/assets/securis.css
+++ b/securis/src/main/webapp/assets/securis.css
@@ -44,4 +44,14 @@
 
 td-paging-bar[hidden] {
 	display: none !important;
-}
\ No newline at end of file
+}
+
+.inner-padding > *{
+	margin-left: 5px;
+	margin-right: 5px;
+}
+
+
+
+
+
diff --git a/securis/src/main/webapp/src/app/app.module.ts b/securis/src/main/webapp/src/app/app.module.ts
index c6e9bd3..dd0d917 100644
--- a/securis/src/main/webapp/src/app/app.module.ts
+++ b/securis/src/main/webapp/src/app/app.module.ts
@@ -18,15 +18,15 @@
 import { LicenseTypesService }  from './resources/license_types';
 import { OrganizationsService }  from './resources/organizations';
 import { ApplicationsService }  from './resources/applications';
-import { UsersService }  from './resources/users';
 import { LicensesService }  from './resources/licenses';
-import { PackListComponent }  from './pack.list.component';
-import { HeroDetailComponent } from './detail.component';
-import { LoginFormComponent } from './login.form.component';
+import { UsersService }  from './resources/users';
 import { MenuComponent }  from './menu.component';
 import { NoMenuComponent }  from './nomenu.component';
 import { FooterComponent }  from './footer.component';
-import { LicenseListComponent } from './license.list.component';
+import { FieldReadonlyComponent }  from './common/utils';
+import { LicenseListComponent } from './listing/license.list.component';
+import { PackListComponent }  from './listing/pack.list.component';
+import { LoginFormComponent } from './forms/login.form.component';
 import { LicenseFormComponent } from './forms/license.form.component';
 
 
@@ -35,6 +35,8 @@
 import { LocaleServiceModule } from './common/i18n';
 import { SeCurisSession } from './common/session';
 import { PackFormComponent } from "./forms/pack.form.component";
+import { ApplicationFormComponent } from './forms/application.form.component';
+import { ApplicationListComponent } from './listing/application.list.component';
 
 @NgModule({
   imports: [
@@ -53,7 +55,8 @@
     appRoutes,
   ],
   declarations: [
-    HeroDetailComponent,
+    ApplicationListComponent,
+    ApplicationFormComponent,
     PackListComponent,
     PackFormComponent,
     LoginFormComponent,
@@ -64,10 +67,11 @@
     HomeComponent,
     MenuComponent,
     NoMenuComponent,
-    FooterComponent    
+    FieldReadonlyComponent,
+    FooterComponent
   ],
   bootstrap: [ HomeComponent ],
-  entryComponents: [ PackFormComponent, LicenseFormComponent ],
+  entryComponents: [  ],
   providers: [
     SeCurisSession,
     UserService,
diff --git a/securis/src/main/webapp/src/app/app.routes.ts b/securis/src/main/webapp/src/app/app.routes.ts
index b3a8270..628797e 100644
--- a/securis/src/main/webapp/src/app/app.routes.ts
+++ b/securis/src/main/webapp/src/app/app.routes.ts
@@ -3,9 +3,13 @@
 import { HomeComponent } from './home.component';
 import { MenuComponent } from './menu.component';
 import { NoMenuComponent } from './nomenu.component';
-import { PackListComponent } from './pack.list.component';
-import { LicenseListComponent } from './license.list.component';
-import { LoginFormComponent } from './login.form.component';
+import { PackListComponent } from './listing/pack.list.component';
+import { LicenseListComponent } from './listing/license.list.component';
+import { LicenseFormComponent } from './forms/license.form.component';
+import { PackFormComponent } from './forms/pack.form.component';
+import { LoginFormComponent } from './forms/login.form.component';
+import { ApplicationFormComponent } from './forms/application.form.component';
+import { ApplicationListComponent } from './listing/application.list.component';
 
 const routes: Routes = [
   {path: 'public',  component: NoMenuComponent, children: [
@@ -16,8 +20,17 @@
     children: [
         {path: 'packs', children: [
           {path: '', component: PackListComponent },
-          {path: ':id/licenses', component: LicenseListComponent },
-        ]}
+          {path: 'create', component: PackFormComponent},
+          {path: 'edit/:packId', component: PackFormComponent},
+
+          {path: ':packId/licenses', component: LicenseListComponent},
+          {path: ':packId/licenses/edit/:licenseId', component: LicenseFormComponent },
+          {path: ':packId/licenses/create', component: LicenseFormComponent },
+
+        ]},
+        {path: 'applications', component: ApplicationListComponent},
+        {path: 'applications/create', component: ApplicationFormComponent},
+        {path: 'applications/edit/:applicationId', component: ApplicationFormComponent}
     ]
   },
 
diff --git a/securis/src/main/webapp/src/app/common/error.checker.ts b/securis/src/main/webapp/src/app/common/error.checker.ts
index b08055e..3c651c3 100644
--- a/securis/src/main/webapp/src/app/common/error.checker.ts
+++ b/securis/src/main/webapp/src/app/common/error.checker.ts
@@ -19,7 +19,6 @@
   @Input() fieldName: string;
 
   constructor(private $L: LocaleService) {
-      console.log('contructor: ' + this.formField);
   }
   
   getFieldErrors() : string[] {
diff --git a/securis/src/main/webapp/src/app/common/i18n.ts b/securis/src/main/webapp/src/app/common/i18n.ts
index 148f562..7e71f18 100644
--- a/securis/src/main/webapp/src/app/common/i18n.ts
+++ b/securis/src/main/webapp/src/app/common/i18n.ts
@@ -2,6 +2,18 @@
 import { ModuleWithProviders, NgModule, Inject, Injectable, Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';
 declare var navigator:any;
 
+declare global {
+    interface String {
+        capitalize(): string;
+        cap(): string;
+    }
+}
+
+String.prototype.capitalize = function() {
+    return this[0].toUpperCase() + this.slice(1);
+}
+String.prototype.cap = String.prototype.capitalize; 
+
 // Use as reference: https://github.com/ngx-translate/core/tree/master/src
 @Injectable()
 export class LocaleService {
@@ -50,9 +62,11 @@
      * It works similar to MessageFormat in Java
      */
     _format(str: string, ...params: string[]) {
-        
-        return str.replace(/\{(\d+)\}/g, function(match, index) {
-            return params[index];
+        var ocur = 0;
+        return str.replace(/\{(\d*)\}/g, function(match, index) {
+            var idx = index === '' ? ocur : +index;
+            ocur += 1;
+            return params[idx];
         });
     };
 
@@ -98,9 +112,10 @@
         }
         // Enviar evento cuando el idioma cambia al $rootScope
         
-        if (arguments.length === 1) return trans_msg;
+        if (params.length === 0) return trans_msg;
         return this._format(trans_msg, ...params);
     }
+
     
 }
 
@@ -134,3 +149,5 @@
 }
 
 
+
+
diff --git a/securis/src/main/webapp/src/app/common/utils.ts b/securis/src/main/webapp/src/app/common/utils.ts
new file mode 100644
index 0000000..7620961
--- /dev/null
+++ b/securis/src/main/webapp/src/app/common/utils.ts
@@ -0,0 +1,50 @@
+
+import {Component, Input} from '@angular/core';
+import {LocaleService} from './i18n';
+
+@Component({
+  selector: 'field-readonly',
+  template: `
+  <div layout="column" class="mat-input-container readonly" >
+		<div class="mat-input-wrapper">
+			<div class="mat-input-table">
+				<div class="mat-input-prefix"></div>
+				<div class="mat-input-infix">
+					<div class="label-value mat-input-element">{{value}}</div>
+					<span class="mat-input-placeholder-wrapper" >
+						<label class="mat-input-placeholder mat-float">
+							<span class="placeholder">{{label}}</span>
+						</label>
+					</span>
+				</div>
+				<div class="mat-input-suffix"></div>
+			</div>
+			<div class="mat-input-underline"></div>
+		</div>
+	</div>`,
+	styles: [`.readonly .mat-input-element {
+				margin-top: 0px !important;
+				color: rgba(0, 0, 0, 0.50);
+			}`,
+			`.readonly .mat-input-element {
+				margin-top: 0px;
+				color: rgba(0, 0, 0, 0.50);
+			}`,
+			`.readonly.mat-input-container {
+				width: 100%;
+			}`]
+})
+export class FieldReadonlyComponent {
+	@Input('value') value: any;
+
+	private _label : string;
+    @Input('label')
+	set label(txt: string) {
+		this._label = this.$L.get(txt);
+	}
+	get label(): string { return this._label; }
+
+	constructor(private $L : LocaleService) {
+
+	}
+}
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/forms/application.form.component.ts b/securis/src/main/webapp/src/app/forms/application.form.component.ts
new file mode 100644
index 0000000..baed64a
--- /dev/null
+++ b/securis/src/main/webapp/src/app/forms/application.form.component.ts
@@ -0,0 +1,64 @@
+import { Http } from '@angular/http';
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
+
+import { ApplicationsService } from '../resources/applications';
+import { LicenseTypesService } from '../resources/license_types';
+import { LocaleService } from '../common/i18n';
+import { IPageChangeEvent } from '@covalent/core';
+import { Component, AfterViewInit } from '@angular/core';
+import { TdMediaService } from '@covalent/core';
+import { FormBase, IComboOption } from './base';
+import { ActivatedRoute, Router } from '@angular/router';
+
+var app_example = { 
+	code: 'CICS',
+  creation_timestamp: 1418384439000,
+  description: 'Wellbore integrity analysis software',
+  id: 1,
+  license_filename: 'config_server.lic',
+  name: 'CurisIntegrity',
+  metadata: 
+   [ { key: 'max_docs',
+       value: '250000',
+       readonly: true,
+       mandatory: true } ] 
+}
+
+@Component({
+  selector: 'application-form',
+  templateUrl: 'src/app/forms/application.form.html'
+})
+export class ApplicationFormComponent extends FormBase {
+
+  fields: any = {
+    'id': '',
+    'code': '',
+    'name': '',
+    'creation_timestamp': '',
+    'license_filename': '',
+    'description': '',
+    'metadata': '',
+    'key': '',
+    'value': '',
+  }
+  constructor(private http: Http,
+              private licenseTypes: LicenseTypesService,
+              private router: Router,
+              private applications: ApplicationsService,
+              toaster: ToastsManager,
+              route: ActivatedRoute,              
+              $L: LocaleService) {
+    super($L, route, toaster, applications, $L.get('application'));
+  }
+
+ 
+  goBack(): void {
+    this.router.navigate([`applications`]);
+  }
+
+ 
+  ngAfterViewInit(): void {
+    super.prepareData('applicationId');
+  }
+}
+
diff --git a/securis/src/main/webapp/src/app/forms/application.form.html b/securis/src/main/webapp/src/app/forms/application.form.html
new file mode 100644
index 0000000..f346418
--- /dev/null
+++ b/securis/src/main/webapp/src/app/forms/application.form.html
@@ -0,0 +1,152 @@
+<td-layout-card-over cardWidth="60">
+	<md-toolbar role="toolbar" class="mat-secondary">
+		<button md-icon-button (click)="goBack()" color="accent">
+			<md-icon>arrow_back</md-icon>
+		</button>
+		<span class="md-title" [innerText]="form_title"></span>
+		<span flex></span>
+		<button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
+	</md-toolbar>
+	<div class="margin" layout-align-gt-xs="center start" layout-fill="" layout-gt-xs="row">
+		<md-card flex="70">
+			<md-card-title>
+				{{form_subtitle}}
+			</md-card-title>
+			<md-divider></md-divider>
+			<md-card-content>
+				<form #applicationForm="ngForm" class="inset">
+					<div layout="column" layout-align="start center">
+						<div layout="row" layout-fill layout-padding>
+							<field-readonly [value]="data.id" label="field.id" flex="15" *ngIf="!isNew"></field-readonly>
+							<div layout="column" layout-fill flex>
+								<md-input-container>
+									<input mdInput maxLength="50" type="text" [(ngModel)]="data.code" name="code" required [readonly]="!isNew" />
+									<md-placeholder>
+										<span i18n="field.code"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('code')" [formField]="applicationForm.controls.code"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container>
+									<input mdInput type="number" [(ngModel)]="data.num_licenses" name="num_licenses" required />
+									<md-placeholder>
+										<span i18n="field.num_licenses"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('num_licenses')" [formField]="applicationForm.controls.num_licenses"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="date" [(ngModel)]="data.init_valid_date" name="init_valid_date" required />
+									<md-placeholder>
+										<span i18n="field.end_valid_date"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('init_valid_date')" [formField]="applicationForm.controls.init_valid_date"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="date" [(ngModel)]="data.end_valid_date" name="end_valid_date" required />
+									<md-placeholder>
+										<span i18n="field.end_valid_date"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('end_valid_date')" [formField]="applicationForm.controls.end_valid_date"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="isNew">
+							<div layout="column" layout-fill flex>
+								<md-select [placeholder]="getFieldName('organization_id')" flex [(ngModel)]="data.organization_id" name="organization_id"
+								 (change)="changeOrg($event)">
+									<md-option *ngFor="let org of organizations" [value]="org.id">
+										{{org.label}}
+									</md-option>
+								</md-select>
+								<error-checker [fieldName]="getFieldName('organization_id')" [formField]="applicationForm.controls.organization_id"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-select flex [placeholder]="getFieldName('license_type_id')" [(ngModel)]="data.license_type_id" name="license_type_id"
+								 (change)="changeLicType($event)">
+									<md-option *ngFor="let lt of licensetypes" [value]="lt.id">
+										{{lt.label}}
+									</md-option>
+								</md-select>
+								<error-checker [fieldName]="getFieldName('license_type_id')" [formField]="applicationForm.controls.license_type_id"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+							<field-readonly [value]="data.organization_name" label="field.organization_id" flex></field-readonly>
+							<field-readonly [value]="data.licensetype_code" label="field.license_type_id" flex></field-readonly>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="number" [(ngModel)]="data.preactivation_valid_period" name="preactivation_valid_period" required />
+									<md-placeholder>
+										<span i18n="field.preactivation_valid_period"></span>
+									</md-placeholder>
+									<md-hint align="end">days</md-hint>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('preactivation_valid_period')" [formField]="applicationForm.controls.preactivation_valid_period"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="number" [(ngModel)]="data.renew_valid_period" name="renew_valid_period" required />
+									<md-placeholder>
+										<span i18n="field.renew_valid_period"></span>
+									</md-placeholder>
+									<md-hint align="end">days</md-hint>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('renew_valid_period')" [formField]="applicationForm.controls.renew_valid_period"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<textarea mdInput type="text" type="text" [(ngModel)]="data.comments" name="comments" maxlength="1024"></textarea>
+									<md-placeholder>
+										<span i18n="field.comments"></span>
+									</md-placeholder>
+									<md-hint align="end">(max 1024)</md-hint>
+								</md-input-container>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+							<field-readonly [value]="data.created_by_name" label="field.created_by" flex></field-readonly>
+							<field-readonly [value]="data.creation_timestamp | date: 'medium'" label="field.creation_timestamp" flex></field-readonly>
+						</div>
+						<div layout="column" layout-fill>
+							<span class="md-title" i18n>License metadata</span>
+							<div layout="row" layout-fill layout-padding *ngFor="let pair of data.metadata">
+								<md-input-container flex="40">
+									<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.key" readonly />
+									<md-placeholder>
+										<span i18n="field.key"></span>
+									</md-placeholder>
+								</md-input-container>
+								<md-input-container flex>
+									<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.value" [readonly]="pair.readonly" [required]="pair.required"
+									/>
+									<md-placeholder>
+										<span i18n="field.value"></span>
+									</md-placeholder>
+								</md-input-container>
+							</div>
+						</div>
+					</div>
+				</form>
+			</md-card-content>
+			<md-divider></md-divider>
+			<md-card-actions>
+				<div layout="row" layout-align="start center" class="margin">
+					<span flex></span>
+					<button [disabled]="!applicationForm.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
+					<button md-button (click)="goBack()">Cancel</button>
+				</div>
+			</md-card-actions>
+		</md-card>
+	</div>
+</td-layout-card-over>
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/forms/base.ts b/securis/src/main/webapp/src/app/forms/base.ts
index 915ad53..708c83e 100644
--- a/securis/src/main/webapp/src/app/forms/base.ts
+++ b/securis/src/main/webapp/src/app/forms/base.ts
@@ -1,5 +1,64 @@
+import { Http } from '@angular/http';
+import { ActivatedRoute } from '@angular/router';
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
+
+import { LocaleService } from '../common/i18n';
+import { SeCurisResourceServices } from '../resources/base';
+
+import { AfterViewInit } from '@angular/core';
+
 
 export interface IComboOption {
 	id: number,
 	label: string
+}
+
+
+export class FormBase {
+	protected form_title: string = '';
+	protected form_subtitle: string = '';
+	protected data: any = {};
+	protected isNew : boolean = true;
+
+	constructor(protected $L: LocaleService, 
+	            protected route: ActivatedRoute,
+				protected toaster: ToastsManager,
+				protected resourceServices: SeCurisResourceServices, 
+				protected resourceName: string ) {
+	}
+
+	public getFieldName(fieldId: string) : string {
+		return this.$L.get(`field.${fieldId}`);
+	}
+
+  	protected loadCombos(): void {}
+
+	save() {
+		var command = this.isNew ? this.resourceServices.create(this.data) : this.resourceServices.modify(this.data.id, this.data);
+		command.subscribe(
+			data => this.toaster.success(this.$L.get('{} saved sucessfully', this.$L.get(this.resourceName).capitalize())),
+			err => {
+				console.error(err);
+				this.toaster.success(this.$L.get('Error saving {}', this.$L.get(this.resourceName)));
+			}
+			);
+	}
+
+	protected prepareData(idparam: string, default_values: any = {}) : void {
+		this.form_title = this.$L.get('{} data', this.resourceName.capitalize());
+		this.isNew = true;
+		!!this.route && this.route.params.subscribe(params => {
+			var eleId = +params[idparam]; // (+) converts string 'id' to a number
+			if (!eleId) {
+				this.data = {};
+				Object.keys(default_values).forEach((k : string) => this.data[k] = default_values[k]);
+				this.form_subtitle = this.$L.get('Create a new {}', this.resourceName) ;
+			} else {
+				this.isNew = false;
+				this.resourceServices.get(eleId).subscribe(eleData => this.data = eleData);
+				this.form_subtitle = this.$L.get('Modify the {} data', this.resourceName) ;
+			}
+		});
+	}
+
 }
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/forms/license.form.component.ts b/securis/src/main/webapp/src/app/forms/license.form.component.ts
index ba627af..e2604f9 100644
--- a/securis/src/main/webapp/src/app/forms/license.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/license.form.component.ts
@@ -1,53 +1,92 @@
 import { Http } from '@angular/http';
 import { LicensesService } from '../resources/licenses';
+import { PacksService } from '../resources/packs';
 import { LocaleService } from '../common/i18n';
 import { TdDataTableService, TdDataTableSortingOrder, ITdDataTableSortChangeEvent, ITdDataTableColumn } from '@covalent/core';
 import { IPageChangeEvent } from '@covalent/core';
-import { Component, AfterViewInit } from '@angular/core';
-import { TdMediaService } from '@covalent/core';
-import { IComboOption } from './base';
+import { AfterViewInit, Component, ViewChild } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+
+import { TdMediaService, TdFileInputComponent } from '@covalent/core';
+import { FormBase, IComboOption } from './base';
+import { ToastsManager } from "ng2-toastr/ng2-toastr";
+
+declare var window: any;
 
 @Component({
   selector: 'license-form',
   templateUrl: 'src/app/forms/license.form.html'
 })
-export class LicenseFormComponent implements AfterViewInit {
+export class LicenseFormComponent extends FormBase {
 
-  form_title: string = 'Title';
+  @ViewChild('requestFileUploader') requestFileUploader : TdFileInputComponent;
+  form_title: string = '';
   form_subtitle: string = '';
   data: any = {};
+  pack: any = null;
   isNew : boolean = true;
 
   constructor(private http: Http,
-              private packs: LicensesService,
-              private $L: LocaleService) {
-      
+              private licenses: LicensesService,
+              private router: Router,
+              private packs: PacksService,
+              toaster: ToastsManager,
+              route: ActivatedRoute,
+              $L: LocaleService) {
+      super($L, route, toaster, licenses, $L.get('license'));
   }
 
-  private loadCombos(): void {
-    /*
-      this.http.get('organization')
-        .map(response => response.json().map((org : any) => <IComboOption>{id: org.id, label: `(${org.code}) ${org.name}`}))
-        .subscribe(
-          data => this.organizations = (<IComboOption[]>data).sort((e1, e2) => e1.label.localeCompare(e2.label)),
-          err => console.error('Error loading orgs')
-        );
-        */
-  }
-
-  log(obj: any) {
-    console.log(obj)
+  requestFileSelected(file: File) : void {
+    console.log(file);
+    console.log(this.requestFileUploader);
+		if (!window.FileReader) { // Browser is not
+          // compatible
+          console.log(this.$L.get("Open your .req file with a text editor and copy&paste the content in the form text field?"));
+          return;
+  	}
+    var reader = new FileReader();
+    reader.onerror = (err) => console.error(err);
+    
+    reader.onload = (event) => {
+      this.data.request_data = reader.result;
+    }
+    reader.readAsText(file); 
+    this.requestFileUploader.clear();
+  } 
+  
+  requestFileUploaded(file: File) : void {
+    console.log(file);
   }
   
-  ngOnInit(): void {
-    this.loadCombos();
-    this.data = {};
-    this.form_title = this.$L.get('License data');
-    this.form_subtitle = this.$L.get(this.isNew ? 'Create a new license': 'Modify the license data') ;
+  createActivationCode() : string {
+      // http://www.ietf.org/rfc/rfc4122.txt
+      var s = new Array(36);
+      var hexDigits = "0123456789abcdef";
+      for (var i = 0; i < 36; i++) {
+          s[i] = hexDigits.substr(Math.random() * 0x10 | 0, 1);
+      }
+      s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
+      s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
+      s[8] = s[13] = s[18] = s[23] = "-";
+
+      var uuid = s.join("");
+      return uuid;
+  }
+
+  goBack(): void {
+    this.router.navigate([`packs/${this.pack.id}/licenses`]);
   }
 
 
   ngAfterViewInit(): void {
+
+    this.route.params.subscribe(params => {
+      var packId = +params['packId']; // (+) converts string 'id' to a number
+      super.prepareData('licenseId', {
+        pack_id: packId,            
+        activation_code: this.createActivationCode()
+      });
+    });
   }
 }
 
diff --git a/securis/src/main/webapp/src/app/forms/license.form.html b/securis/src/main/webapp/src/app/forms/license.form.html
index df65d4d..0d4ec82 100644
--- a/securis/src/main/webapp/src/app/forms/license.form.html
+++ b/securis/src/main/webapp/src/app/forms/license.form.html
@@ -1,75 +1,124 @@
-<form #packForm="ngForm" class="inset" (keyup.enter)="save()">
-	<md-card>
-		<md-card-title>
-			{{form_title}}
-		</md-card-title>
-		<md-card-subtitle>
-			{{form_subtitle}}
-		</md-card-subtitle>
-<md-divider></md-divider>
-		<md-card-content>
-	<div layout="column" layout-align="start center" layout-fill>
-		<div layout="row" layout-fill layout-padding>
-			<div layout="column" layout-fill  flex="50">
-			<md-input-container>
-				<input mdInput maxLength="50" type="text" [(ngModel)]="data.code" name="code" required />
-				<md-placeholder>
-          			<span i18n>Code</span>
-        		</md-placeholder>
-			</md-input-container>
-			{{log(packForm.controls)}}
-			<div *ngIf="packForm.controls.code?.touched && packForm.controls.code.invalid" layout="column">
-				<span *ngIf="packForm.controls.code.errors.required" align="end">Code is required</span>
-				<span align="end">Code is ok</span>
+<td-layout-card-over cardWidth="60">
+	<md-toolbar role="toolbar" class="mat-secondary">
+		<button md-icon-button (click)="goBack()" color="accent">
+			<md-icon>arrow_back</md-icon>
+		</button>
+		<span>{{form_title}}</span>
+		<span flex></span>
+		<button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
+		<md-toolbar-row class="inner-padding" *ngIf="!!pack" >
+			<div>
+				<span i18n>Pack</span>: {{pack.code}}
 			</div>
+			<div class="inner-padding" flex="70" style="margin-left: 10px;" layout-align="start center" layout="row">
+				<md-chip selected [mdTooltip]="$L.get('field.application_name')" color="primary">{{pack.application_name}} </md-chip>
+				<md-chip selected [mdTooltip]="$L.get('field.organization_id')" color="accent">{{pack.organization_name}} </md-chip>
+				<md-chip selected [mdTooltip]="$L.get('field.license_type_id')" color="accent">{{pack.licensetype_code}} </md-chip>
 			</div>
-	<!-- TODO: <div class="alert inline-alert alert-warning" ng-show="packForm.code.$invalid">
-		<span class="glyphicon glyphicon-warning-sign"></span> 
-		<span ng-show="packForm.code.$error.maxlength" ng-bind="maxLengthErrorMsg('Code', maxlength.code)" 
-		class="ng-binding ng-hide">Code length is too long (max: 50).</span> 
-		<span ng-show="packForm.code.$error.required" ng-bind="mandatoryFieldErrorMsg('Code')" class="ng-binding">'Code' is required.</span>
-	</div> -->
-			<md-input-container flex="50">
-				<input mdInput type="number" type="text" [(ngModel)]="data.num_licenses" name="num_licenses" required />
-				<md-placeholder>
-          			<span i18n>Num. licenses</span>
-        		</md-placeholder>
-			</md-input-container>
-		</div>
-		<div layout="row" layout-align="start center" layout-fill layout-padding>
-			<md-input-container flex>
-				<input mdInput type="date" type="text" [(ngModel)]="data.init_valid_date" name="init_valid_date" required />
-				<md-placeholder>
-          			<span i18n>Initial date</span>
-        		</md-placeholder>
-				<md-hint align="end">YYYY-MM-DD</md-hint>
-			</md-input-container>
-			<md-input-container flex>
-				<input mdInput type="date" type="text" [(ngModel)]="data.end_valid_date" name="end_valid_date" required />
-				<md-placeholder>
-          			<span i18n>End date</span>
-        		</md-placeholder>
-				<md-hint align="end">YYYY-MM-DD</md-hint>
-			</md-input-container>
-		</div>
-		<div layout="row" layout-fill layout-padding>
-			<md-select flex placeholder="Organization" [(ngModel)]="data.organization_id" name="organization_id">
-				<md-option *ngFor="let org of organizations" [value]="org.id">
-					{{org.label}}
-				</md-option>
-			</md-select>
-			<md-select flex placeholder="License type" [(ngModel)]="data.license_type_id" name="license_type_id">
-				<md-option *ngFor="let lt of licensetypes" [value]="lt.id">
-					{{lt.label}}
-				</md-option>
-			</md-select>
-		</div>
+			<span flex></span>
+			<md-chip-list>
+				<md-chip [mdTooltip]="$L.get('field.num_available')" color="secondary" [class.bgc-red-A100]="pack.num_available <= 0">
+					<span i18n="field.num_available"></span>: {{pack.num_available}} </md-chip>
+			</md-chip-list>
+		</md-toolbar-row>
+	</md-toolbar>
+	<div class="margin" layout-align-gt-xs="center start" layout-fill="" layout-gt-xs="row">
+			<md-card  flex="70">
+				<md-card-title>
+					{{form_subtitle}}
+				</md-card-title>
+				<md-divider></md-divider>
+				<md-card-content>
+					<form #licenseForm="ngForm" class="inset" (keyup.enter)="save()">
+						<div layout="column" layout-align="start center">
+							<div layout="row" layout-fill layout-padding>
+								<field-readonly [value]="data.id" label="field.id" flex="20" *ngIf="!isNew"></field-readonly>
+								<field-readonly [value]="data.code" label="field.code" flex></field-readonly>
+							</div>
+							<div layout="row" layout-fill layout-padding>
+								<field-readonly [value]="data.activation_code" label="field.activation_code" flex></field-readonly>
+							</div>
+							<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+								<field-readonly [value]="data.expiration_date | date: 'dateMedium'" label="field.expiration_date" flex></field-readonly>
+								<field-readonly [value]="licenses.getStatusName(data.status)" label="field.status" flex></field-readonly>
+							</div>
+							<div layout="row" layout-fill layout-padding>
+								<div layout="column" layout-fill flex>
+									<md-input-container flex>
+										<input mdInput type="text" [(ngModel)]="data.full_name" name="full_name" required maxlength="200" />
+										<md-placeholder>
+											<span i18n="field.full_name"></span>
+										</md-placeholder>
+									</md-input-container>
+									<error-checker [fieldName]="$L.get('field.full_name')" [formField]="licenseForm.controls.full_name"></error-checker>
+								</div>
+								<div layout="column" layout-fill flex>
+									<md-input-container flex>
+										<input mdInput type="email" [(ngModel)]="data.email" name="email" required maxlength="200" />
+										<md-placeholder>
+											<span i18n="field.email"></span>
+										</md-placeholder>
+									</md-input-container>
+									<error-checker [fieldName]="$L.get('field.full_name')" [formField]="licenseForm.controls.email"></error-checker>
+								</div>
+							</div>
+							<div layout="row" layout-fill layout-padding>
+								<div layout="column" layout-fill flex>
+									<md-input-container flex>
+										<textarea mdInput type="text" type="text" [(ngModel)]="data.request_data" name="request_data" maxlength="2048"></textarea>
+										<md-placeholder>
+											<span i18n="field.request_data"></span>
+										</md-placeholder>
+										<md-hint align="end">(max 2048)</md-hint>
+									</md-input-container>
+								</div>
+								<td-file-input #requestFileUploader (select)="requestFileSelected($event)" accept=".req,.txt,.json">
+									<md-icon>attachment</md-icon>
+								</td-file-input>
+							</div>
+							<div layout="row" layout-fill layout-padding>
+								<div layout="column" layout-fill flex>
+									<md-input-container flex>
+										<textarea mdInput type="text" type="text" [(ngModel)]="data.comments" name="comments" maxlength="1024"></textarea>
+										<md-placeholder>
+											<span i18n="field.comments"></span>
+										</md-placeholder>
+										<md-hint align="end">(max 1024)</md-hint>
+									</md-input-container>
+								</div>
+							</div>
+							<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+								<field-readonly [value]="data.created_by_id" label="field.created_by" flex></field-readonly>
+								<field-readonly [value]="data.creation_date | date: 'medium'" label="field.creation_date" flex></field-readonly>
+							</div>
+							<div layout="column" layout-fill>
+								<span class="md-title" i18n>License metadata</span>
+								<div layout="row" layout-fill layout-padding *ngFor="let pair of pack?.metadata">
+									<md-input-container flex="40">
+										<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.key" readonly />
+										<md-placeholder>
+											<span i18n="field.key"></span>
+										</md-placeholder>
+									</md-input-container>
+									<md-input-container flex>
+										<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.value" readonly />
+										<md-placeholder>
+											<span i18n="field.value"></span>
+										</md-placeholder>
+									</md-input-container>
+								</div>
+							</div>
+						</div>
+					</form>
+				</md-card-content>
+				<md-divider></md-divider>
+				<md-card-actions>
+					<div layout="row" layout-align="start center" class="margin">
+						<span flex></span>
+						<button [disabled]="!licenseForm.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
+						<button md-button (click)="goBack()">Cancel</button>
+					</div>
+				</md-card-actions>
+			</md-card>
 	</div>
-</md-card-content>
-<md-divider></md-divider>
-<md-card-actions>
-	<button [disabled]="!packForm.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
-	<button md-button md-dialog-close>Cancel</button>
-</md-card-actions>
-</md-card>
-</form>	
+</td-layout-card-over>
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/login.form.component.ts b/securis/src/main/webapp/src/app/forms/login.form.component.ts
similarity index 90%
rename from securis/src/main/webapp/src/app/login.form.component.ts
rename to securis/src/main/webapp/src/app/forms/login.form.component.ts
index 972ac97..a0acd24 100644
--- a/securis/src/main/webapp/src/app/login.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/login.form.component.ts
@@ -1,7 +1,7 @@
 import { Http } from '@angular/http';
 import { Router } from '@angular/router';
 import { AfterViewInit, Component, Input } from '@angular/core';
-import { UserService } from './user.service';
+import { UserService } from '../user.service';
 import { ToastsManager } from 'ng2-toastr/ng2-toastr';
 
 class LoginData {
@@ -11,7 +11,7 @@
 
 @Component({
   selector: 'login-form',
-  templateUrl: "src/app/login.form.html"
+  templateUrl: "src/app/forms/login.form.html"
 })
 export class LoginFormComponent implements AfterViewInit {
   data = new LoginData();
diff --git a/securis/src/main/webapp/src/app/login.form.html b/securis/src/main/webapp/src/app/forms/login.form.html
similarity index 100%
rename from securis/src/main/webapp/src/app/login.form.html
rename to securis/src/main/webapp/src/app/forms/login.form.html
diff --git a/securis/src/main/webapp/src/app/forms/pack.form.component.ts b/securis/src/main/webapp/src/app/forms/pack.form.component.ts
index 49b41ec..e798be4 100644
--- a/securis/src/main/webapp/src/app/forms/pack.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/pack.form.component.ts
@@ -8,7 +8,8 @@
 import { IPageChangeEvent } from '@covalent/core';
 import { Component, AfterViewInit } from '@angular/core';
 import { TdMediaService } from '@covalent/core';
-import { IComboOption } from './base';
+import { IComboOption, FormBase } from './base';
+import { ActivatedRoute, Router } from '@angular/router';
 
 
 
@@ -16,10 +17,8 @@
   selector: 'pack-form',
   templateUrl: 'src/app/forms/pack.form.html'
 })
-export class PackFormComponent implements AfterViewInit {
+export class PackFormComponent extends FormBase implements AfterViewInit {
 
-  form_title: string = 'Title';
-  form_subtitle: string = '';
   organizations : IComboOption[];
   licensetypes : IComboOption[];
   data: any = {};
@@ -44,18 +43,20 @@
     'value': '',
   }
   constructor(private http: Http,
-              private toaster: ToastsManager,
+              toaster: ToastsManager,
               private licenseTypes: LicenseTypesService,
+              route: ActivatedRoute,
+              private router: Router,
               private packs: PacksService,
-              private $L: LocaleService) {
-      Object.keys(this.fields).forEach(k => this.fields[k] = $L.get(`field.${k}`));
+              $L: LocaleService) {
+    super($L, route, toaster, packs, $L.get('pack'));
   }
 
   public getFieldName(fieldId: string) : string {
     return this.fields[fieldId];
   }
 
-  private loadCombos(): void {
+  loadCombos(): void {
       this.http.get('organization')
         .map(response => response.json().map((org : any) => <IComboOption>{id: org.id, label: `(${org.code}) ${org.name}`}))
         .subscribe(
@@ -70,15 +71,9 @@
         );
   }
 
-  save() {
-      var command = this.isNew ? this.packs.create(this.data) : this.packs.modify(this.data.id, this.data);
-      command.subscribe(
-          data => this.toaster.success(this.$L.get('Pack saved sucessfully')),
-          err => {
-            console.error(err);
-            this.toaster.success(this.$L.get('Error saving pack'));
-          }
-        );
+
+  goBack(): void {
+    this.router.navigate([`packs`]);
   }
 
   changeLicType(event: any) {
@@ -99,16 +94,15 @@
   } 
   
   ngOnInit(): void {
-    this.loadCombos();
-    if (this.isNew) {
-      this.data.status = PACK_STATUS.CREATED;
-    }
-    this.form_title = this.$L.get('Pack data');
-    this.form_subtitle = this.$L.get(this.isNew ? 'Create a new licenses pack': 'Modify the licenses pack data') ;
+
   }
 
 
   ngAfterViewInit(): void {
+    this.loadCombos();
+    super.prepareData('packId', {
+      status: PACK_STATUS.CREATED
+    });
   }
 }
 
diff --git a/securis/src/main/webapp/src/app/forms/pack.form.html b/securis/src/main/webapp/src/app/forms/pack.form.html
index 9575db2..e509765 100644
--- a/securis/src/main/webapp/src/app/forms/pack.form.html
+++ b/securis/src/main/webapp/src/app/forms/pack.form.html
@@ -1,189 +1,160 @@
-<md-toolbar>
-	<span md-dialog-title>{{form_title}}</span>
-	<span flex></span>
-	<button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
-	<button md-icon-button md-dialog-close><md-icon>close</md-icon></button>
-</md-toolbar>
-<p class="md-subhead">{{form_subtitle}}</p>
-<md-divider></md-divider>
-<form #packForm="ngForm" class="inset" >
-<div layout="column" >
-<md-dialog-content>
-	<div layout="column" layout-align="start center">
-		<div layout="row" layout-fill layout-padding>
-			<div layout="column" layout-fill  flex="15" *ngIf="!isNew">
-				<md-input-container>
-					<input mdInput maxLength="50" type="text" [(ngModel)]="data.id" name="id" required [readonly]="!isNew" />
-					<md-placeholder>
-						<span i18n="field.id"></span>
-					</md-placeholder>
-				</md-input-container>
-			</div>
-			<div layout="column" layout-fill  flex>
-				<md-input-container>
-					<input mdInput maxLength="50" type="text" [(ngModel)]="data.code" name="code" required [readonly]="!isNew" />
-					<md-placeholder>
-						<span i18n="field.code"></span>
-					</md-placeholder>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('code')" [formField]="packForm.controls.code"></error-checker>
-			</div>
-			<div layout="column" layout-fill flex>
-				<md-input-container>
-					<input mdInput type="number"  [(ngModel)]="data.num_licenses" name="num_licenses" required />
-					<md-placeholder>
-						<span i18n="field.num_licenses"></span>
-					</md-placeholder>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('num_licenses')" [formField]="packForm.controls.num_licenses"></error-checker>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding>
-			<div layout="column" layout-fill flex>
-				<md-checkbox labelPosition="after" [(ngModel)]="data.license_preactivation" name="license_preactivation">
-					<span i18n="field.license_preactivation"></span>
-				</md-checkbox>
-			</div>
-			<div layout="column" layout-fill flex *ngIf="!isNew">
-				<div layout="column" class="mat-input-container" flex>
-					<label class="mat-input-placeholder mat-float">
-						<span class="placeholder" i18n="field.status"></span>
-					</label>
-					<div class="label-value mat-input-element">{{packs.getStatusName(data.status)}}</div>
+<td-layout-card-over cardWidth="60">
+	<md-toolbar role="toolbar" class="mat-secondary">
+		<button md-icon-button (click)="goBack()" color="accent">
+			<md-icon>arrow_back</md-icon>
+		</button>
+		<span class="md-title" i18n>{{form_title}}</span>
+		<span flex></span>
+		<button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
+	</md-toolbar>
+	<div class="margin" layout-align-gt-xs="center start" layout-fill="" layout-gt-xs="row">
+		<md-card flex="70">
+			<md-card-title>
+				{{form_subtitle}}
+			</md-card-title>
+			<md-divider></md-divider>
+			<md-card-content>
+				<form #packForm="ngForm" class="inset">
+					<div layout="column" layout-align="start center">
+						<div layout="row" layout-fill layout-padding>
+							<field-readonly [value]="data.id" label="field.id" flex="15" *ngIf="!isNew"></field-readonly>
+							<div layout="column" layout-fill flex>
+								<md-input-container>
+									<input mdInput maxLength="50" type="text" [(ngModel)]="data.code" name="code" required [readonly]="!isNew" />
+									<md-placeholder>
+										<span i18n="field.code"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('code')" [formField]="packForm.controls.code"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container>
+									<input mdInput type="number" [(ngModel)]="data.num_licenses" name="num_licenses" required />
+									<md-placeholder>
+										<span i18n="field.num_licenses"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('num_licenses')" [formField]="packForm.controls.num_licenses"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-checkbox labelPosition="after" [(ngModel)]="data.license_preactivation" name="license_preactivation">
+									<span i18n="field.license_preactivation"></span>
+								</md-checkbox>
+							</div>
+							<field-readonly [value]="packs.getStatusName(data.status)" label="field.status" flex *ngIf="!isNew"></field-readonly>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="date" [(ngModel)]="data.init_valid_date" name="init_valid_date" required />
+									<md-placeholder>
+										<span i18n="field.end_valid_date"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('init_valid_date')" [formField]="packForm.controls.init_valid_date"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="date" [(ngModel)]="data.end_valid_date" name="end_valid_date" required />
+									<md-placeholder>
+										<span i18n="field.end_valid_date"></span>
+									</md-placeholder>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('end_valid_date')" [formField]="packForm.controls.end_valid_date"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="isNew">
+							<div layout="column" layout-fill flex>
+								<md-select [placeholder]="getFieldName('organization_id')" flex [(ngModel)]="data.organization_id" name="organization_id"
+								 (change)="changeOrg($event)">
+									<md-option *ngFor="let org of organizations" [value]="org.id">
+										{{org.label}}
+									</md-option>
+								</md-select>
+								<error-checker [fieldName]="getFieldName('organization_id')" [formField]="packForm.controls.organization_id"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-select flex [placeholder]="getFieldName('license_type_id')" [(ngModel)]="data.license_type_id" name="license_type_id"
+								 (change)="changeLicType($event)">
+									<md-option *ngFor="let lt of licensetypes" [value]="lt.id">
+										{{lt.label}}
+									</md-option>
+								</md-select>
+								<error-checker [fieldName]="getFieldName('license_type_id')" [formField]="packForm.controls.license_type_id"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+							<field-readonly [value]="data.organization_name" label="field.organization_id" flex></field-readonly>
+							<field-readonly [value]="data.licensetype_code" label="field.license_type_id" flex></field-readonly>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="number" [(ngModel)]="data.preactivation_valid_period" name="preactivation_valid_period" required />
+									<md-placeholder>
+										<span i18n="field.preactivation_valid_period"></span>
+									</md-placeholder>
+									<md-hint align="end">days</md-hint>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('preactivation_valid_period')" [formField]="packForm.controls.preactivation_valid_period"></error-checker>
+							</div>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<input mdInput type="number" [(ngModel)]="data.renew_valid_period" name="renew_valid_period" required />
+									<md-placeholder>
+										<span i18n="field.renew_valid_period"></span>
+									</md-placeholder>
+									<md-hint align="end">days</md-hint>
+								</md-input-container>
+								<error-checker [fieldName]="getFieldName('renew_valid_period')" [formField]="packForm.controls.renew_valid_period"></error-checker>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding>
+							<div layout="column" layout-fill flex>
+								<md-input-container flex>
+									<textarea mdInput type="text" type="text" [(ngModel)]="data.comments" name="comments" maxlength="1024"></textarea>
+									<md-placeholder>
+										<span i18n="field.comments"></span>
+									</md-placeholder>
+									<md-hint align="end">(max 1024)</md-hint>
+								</md-input-container>
+							</div>
+						</div>
+						<div layout="row" layout-fill layout-padding *ngIf="!isNew">
+							<field-readonly [value]="data.created_by_name" label="field.created_by" flex></field-readonly>
+							<field-readonly [value]="data.creation_timestamp | date: 'medium'" label="field.creation_timestamp" flex></field-readonly>
+						</div>
+						<div layout="column" layout-fill>
+							<span class="md-title" i18n>License metadata</span>
+							<div layout="row" layout-fill layout-padding *ngFor="let pair of data.metadata">
+								<md-input-container flex="40">
+									<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.key" readonly />
+									<md-placeholder>
+										<span i18n="field.key"></span>
+									</md-placeholder>
+								</md-input-container>
+								<md-input-container flex>
+									<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.value" [readonly]="pair.readonly" [required]="pair.required"
+									/>
+									<md-placeholder>
+										<span i18n="field.value"></span>
+									</md-placeholder>
+								</md-input-container>
+							</div>
+						</div>
+					</div>
+				</form>
+			</md-card-content>
+			<md-divider></md-divider>
+			<md-card-actions>
+				<div layout="row" layout-align="start center" class="margin">
+					<span flex></span>
+					<button [disabled]="!packForm.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
+					<button md-button (click)="goBack()">Cancel</button>
 				</div>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding>
-			<div layout="column" layout-fill flex>
-				<md-input-container flex>
-					<input mdInput type="date" [(ngModel)]="data.init_valid_date" name="init_valid_date" required />
-					<md-placeholder>
-						<span i18n="field.end_valid_date"></span>
-					</md-placeholder>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('init_valid_date')" [formField]="packForm.controls.init_valid_date"></error-checker>
-			</div>
-			<div layout="column" layout-fill flex>
-				<md-input-container flex>
-					<input mdInput type="date" [(ngModel)]="data.end_valid_date" name="end_valid_date" required />
-					<md-placeholder>
-						<span i18n="field.end_valid_date"></span>
-					</md-placeholder>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('end_valid_date')" [formField]="packForm.controls.end_valid_date"></error-checker>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding *ngIf="isNew">
-			<div layout="column" layout-fill flex>
-				<md-select [placeholder]="getFieldName('organization_id')" flex [(ngModel)]="data.organization_id" name="organization_id" (change)="changeOrg($event)">
-					<md-option *ngFor="let org of organizations" [value]="org.id">
-						{{org.label}}
-					</md-option>
-				</md-select>
-				<error-checker [fieldName]="getFieldName('organization_id')" [formField]="packForm.controls.organization_id"></error-checker>
-			</div>
-			<div layout="column" layout-fill flex>
-				<md-select flex [placeholder]="getFieldName('license_type_id')" [(ngModel)]="data.license_type_id" name="license_type_id" (change)="changeLicType($event)">
-					<md-option *ngFor="let lt of licensetypes" [value]="lt.id">
-						{{lt.label}}
-					</md-option>
-				</md-select>
-				<error-checker [fieldName]="getFieldName('license_type_id')" [formField]="packForm.controls.license_type_id"></error-checker>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding *ngIf="!isNew">
-			<div layout="column" layout-fill flex>
-				<div layout="column" class="mat-input-container" flex>
-					<label class="mat-input-placeholder mat-float">
-						<span class="placeholder" i18n="field.organization_id"></span>
-					</label>
-					<div class="label-value mat-input-element">{{data.organization_name}}</div>
-				</div>
-			</div>
-			<div layout="column" layout-fill flex>
-				<div layout="column" class="mat-input-container" flex>
-					<label class="mat-input-placeholder mat-float">
-						<span class="placeholder" i18n="field.license_type_id"></span>
-					</label>
-					<div class="label-value mat-input-element">{{data.licensetype_code}}</div>
-				</div>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding >
-			<div layout="column" layout-fill flex>
-				<md-input-container flex>
-					<input mdInput type="number"  [(ngModel)]="data.preactivation_valid_period" name="preactivation_valid_period" required />
-					<md-placeholder>
-						<span i18n="field.preactivation_valid_period"></span>
-					</md-placeholder>
-					<md-hint align="end">days</md-hint>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('preactivation_valid_period')" [formField]="packForm.controls.preactivation_valid_period"></error-checker>
-			</div>
-			<div layout="column" layout-fill flex>
-				<md-input-container flex>
-					<input mdInput type="number"[(ngModel)]="data.renew_valid_period" name="renew_valid_period" required />
-					<md-placeholder>
-						<span i18n="field.renew_valid_period"></span>
-					</md-placeholder>
-					<md-hint align="end">days</md-hint>
-				</md-input-container>
-				<error-checker [fieldName]="getFieldName('renew_valid_period')" [formField]="packForm.controls.renew_valid_period"></error-checker>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding>
-			<div layout="column" layout-fill flex>
-				<md-input-container flex>
-					<textarea mdInput type="text" type="text" [(ngModel)]="data.comments" name="comments" maxlength="1024" ></textarea>
-					<md-placeholder>
-						<span i18n="field.comments"></span>
-					</md-placeholder>
-					<md-hint align="end">(max 1024)</md-hint>
-				</md-input-container>
-			</div>
-		</div>
-		<div layout="row" layout-fill layout-padding *ngIf="!isNew">
-			<div layout="column" layout-fill flex>
-				<div layout="column" class="mat-input-container" flex>
-					<label class="mat-input-placeholder mat-float">
-						<span class="placeholder" i18n="field.created_by_name"></span>
-					</label>
-					<div class="label-value mat-input-element">{{data.created_by_name}}</div>
-				</div>
-			</div>
-			<div layout="column" layout-fill flex>
-				<div layout="column" class="mat-input-container" flex>
-					<label class="mat-input-placeholder mat-float">
-						<span class="placeholder" i18n="field.creation_timestamp"></span>
-					</label>
-					<div class="label-value mat-input-element">{{data.creation_timestamp | date: 'medium'}}</div>
-				</div>
-			</div>
-		</div>
-		<div layout="column" layout-fill>
-			<span class="md-title" i18n>License metadata</span>
-			<div layout="row" layout-fill layout-padding *ngFor="let pair of data.metadata">
-				<md-input-container flex="40">
-					<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.key" readonly />
-					<md-placeholder>
-						<span i18n="field.key"></span>
-					</md-placeholder>
-				</md-input-container>
-				<md-input-container flex>
-					<input mdInput type="text" [ngModelOptions]="{standalone: true}" [(ngModel)]="pair.value" [readonly]="pair.readonly" [required]="pair.required" />
-					<md-placeholder>
-						<span i18n="field.value"></span>
-					</md-placeholder>
-				</md-input-container>
-			</div>
-		</div>
+			</md-card-actions>
+		</md-card>
 	</div>
-</md-dialog-content>
-<div flex></div>
-<md-divider></md-divider>
-<md-dialog-actions layout="row" layout-align="end center">
-		<button [disabled]="!packForm.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
-		<button md-button md-dialog-close>Cancel</button>
-</md-dialog-actions>
-</div>
-</form>	
+</td-layout-card-over>
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/license.list.component.ts b/securis/src/main/webapp/src/app/license.list.component.ts
deleted file mode 100644
index 2ffc546..0000000
--- a/securis/src/main/webapp/src/app/license.list.component.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-import { LocaleService } from './common/i18n';
-import { ActivatedRoute, Router } from '@angular/router';
-import { MdDialog, MdDialogConfig } from '@angular/material';
-import { TdDataTableService, TdPagingBarComponent, TdDataTableSortingOrder, ITdDataTableSortChangeEvent, ITdDataTableColumn } from '@covalent/core';
-import { IPageChangeEvent } from '@covalent/core';
-import { Component, AfterViewInit, ViewChild } from '@angular/core';
-import { TdMediaService } from '@covalent/core';
-import { LicensesService } from './resources/licenses';
-import { PacksService } from './resources/packs';
-import { Location } from '@angular/common';
-
-import { LicenseFormComponent } from './forms/license.form.component';
-
-var lic_example = { activation_code: '19fa8d30-29cb-4b59-81b5-3837af8204b6',
-  code: 'CISA02-494-1',
-  code_suffix: 1,
-  created_by_id: '_client',
-  creation_timestamp: 1447848747000,
-  email: 'ccalvo@curisit.net',
-  expiration_date: 1450440747000,
-  full_name: 'César SA',
-  id: 110,
-  licenseData: '{"appCode":"CISA","appName":"CurisIntegrity SA","licenseCode":"CISA02-494-1","activationCode":"19fa8d30-29cb-4b59-81b5-3837af8204b6","expirationDate":1450440746790,"arch":"x86_64","osName":"Mac OS X","macAddresses":["60-03-08-95-AE-D0","B6-2B-33-E9-64-2D"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f","metadata":{"maxWellLifeLines":"50","simulationModes":"A1,A2,N1,QL"},"signature":"Tejun4bNbknxOyEmPaO/fGfGhv4URhVON/7bESxbODFWMJYKQqOPHrDiSUMlf6RbfWSVg2Dry8bY1WX881QGjTkBaHeDJKCy1EaJBwJ2nv9TYSMOiRj0eqMNYWE9/oLpvufHylAkPUpZwXVkSzTxmN+RvWa2Xt4Fu7xN+4PDHV4t7PSq7QwsFlD9ArgYC6Vx+zuL9WZANBtJ2gU/gKOE0CU0KjsB49RGQSFS/G27+H/YuDkCiQq7PC7VdVwYONQ2HO91fyPvInIrzDC5+sWHcUAqSCop//8klMy03hWl6VvAlaSP7kNM3KadyqXIJ3tx4Jwm1W+gBb3tngHzVCpYmw=="}',
-  modification_timestamp: 1447848747000,
-  pack_code: 'CISA02',
-  pack_id: 18,
-  request_data: '{"appCode":"CISA","activationCode":"19fa8d30-29cb-4b59-81b5-3837af8204b6","arch":"x86_64","osName":"Mac OS X","macAddresses":["60-03-08-95-AE-D0","B6-2B-33-E9-64-2D"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f"}',
-  status: 'AC' }
-
-const DIALOG_OPTIONS : MdDialogConfig = {
-  height: '80%', // can be px or %
-  width: '45%', // can be px or %
-}
-
-@Component({
-  selector: 'license-list',
-  templateUrl: 'src/app/license.list.component.html'
-})
-export class LicenseListComponent implements AfterViewInit {
-  data: any[] = [];
-  @ViewChild('pagingBar') pagingBar : TdPagingBarComponent ;
-
-  pack: any = null;
-  columns: ITdDataTableColumn[] = [
-    { name: 'code', label: 'Code', tooltip: 'License code' },
-    { name: 'full_name', label: 'User name' },
-    { name: 'email', label: 'User email' },
-    { name: 'expiration_date', label: 'Expiration date' },
-    { name: 'status', label: 'Status' },
-    { name: 'menu', label: '' }
-  ];
-
-  filteredData: any[] = this.data;
-  filteredTotal: number = this.data.length;
-
-  searchTerm: string = '';
-  fromRow: number = 1;
-  currentPage: number = 1;
-  pageSize: number = 10;
-  sortBy: string = 'expiration_date';
-  sortOrder: TdDataTableSortingOrder = TdDataTableSortingOrder.Descending;
-  filteredItems = this.data.length;
-  license_menu_options : any[] = [{
-    icon: 'edit',
-    command: 'edit',
-    name: 'Edit'
-  },{
-    icon: 'cancel',
-    command: 'cancel',
-    name: 'Cancel'
-  }]
-  
-  licenseAction(action: any) {
-    console.log(action.command);
-  }
-
-  isActionAvailable(pack : any) : boolean {
-    return true;
-  }
-
-  constructor(private _dataTableService: TdDataTableService,
-    private media: TdMediaService,
-    private $L: LocaleService,
-    private router: Router,
-    private location: Location,
-    private route: ActivatedRoute,
-    private dialog: MdDialog,
-    private licenseForm: LicenseFormComponent,
-    private licenses: LicensesService,
-    private packs: PacksService) {
-  }
-
-  ngOnInit(): void {
-    this.route.params.subscribe(params => {
-        var packId = +params['id']; // (+) converts string 'id' to a number
-        this.licenses.getByPack(packId).subscribe(
-          list => {
-            this.data = list;
-            this.filter();
-          },
-          err => console.error(err)
-        );
-        this.packs.get(packId).subscribe(
-          packData => {
-            this.pack = packData;
-          },
-          err => console.error(err)
-        );
-      });
-  }
-
-  goBack() : void {
-    this.location.back();
-  }
-
-  isLicenseExpired(lic: any): boolean {
-    return lic.expiration_date < (new Date().getTime());
-  }
-
-  createLicense() : void {
-    let ref = this.dialog.open(LicenseFormComponent, DIALOG_OPTIONS);
-    
-    ref.componentInstance.isNew = true;
-    ref.componentInstance.data = {};
-    ref.afterClosed().subscribe(result => {
-      this.filter();
-    });
-  
-  }
-
-  editLicense(lic: any) : void {
-    let ref = this.dialog.open(LicenseFormComponent, DIALOG_OPTIONS);
-    ref.componentInstance.isNew = false;
-    ref.componentInstance.data = lic;
-    ref.afterClosed().subscribe(result => {
-      this.filter();
-    });
-  }
-
-
-  sort(sortEvent: ITdDataTableSortChangeEvent): void {
-    this.sortBy = sortEvent.name;
-    this.sortOrder = sortEvent.order;
-    this.filter();
-  }
-
-  search(searchTerm: string): void {
-    this.searchTerm = searchTerm;
-    this.filter();
-  }
-
-  page(pagingEvent: IPageChangeEvent): void {
-    this.fromRow = pagingEvent.fromRow;
-    this.currentPage = pagingEvent.page;
-    this.pageSize = pagingEvent.pageSize;
-    this.filter();
-  }
-
-  loadData() {
-
-  }
-
-  filter(): void {
-    let newData: any[] = this.data;
-    newData = this._dataTableService.filterData(newData, this.searchTerm, true);
-    this.filteredTotal = newData.length;
-    this.filteredItems = newData.length;
-    newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder);
-    newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize);
-    this.filteredData = newData;
-  }
-
-  ngAfterViewInit(): void {
-    this.media.broadcast();
-
-  }
-}
-
diff --git a/securis/src/main/webapp/src/app/listing/application.list.component.html b/securis/src/main/webapp/src/app/listing/application.list.component.html
new file mode 100644
index 0000000..ee92101
--- /dev/null
+++ b/securis/src/main/webapp/src/app/listing/application.list.component.html
@@ -0,0 +1,37 @@
+<td-layout-card-over cardWidth="70">
+  <md-toolbar role="toolbar" class="mat-secondary">
+    <span class="push-left-sm">
+        <span class="md-title" i18n>Applications</span>
+    </span>
+    <span class="push-left-sm" *ngIf="filteredItems < data.length">
+        <span class="md-body-1">{{filteredItems}} of {{data.length}} applications filtered</span>
+    </span>
+    <td-search-box #searchBox class="push-right-sm" placeholder="Search here" (searchDebounce)="search($event)" flex>
+    </td-search-box>
+    <button md-mini-fab color="accent" (click)="create()" [mdTooltip]="$L.get('Create a new application')">
+        <md-icon>add</md-icon>
+      </button>
+  </md-toolbar>
+ 	<div flex="84" layout-align="center end" layout="column">
+    <td-data-table 
+      [data]="filteredData" 
+      [columns]="columns" 
+      [sortable]="true"
+      [sortBy]="sortBy"
+      (sortChange)="sort($event)"
+      style="width: 100%">
+      <template tdDataTableTemplate="creation_timestamp" let-row="row" let-value="value">
+         <span>{{value | date: 'medium'}}</span>
+      </template>
+      <template tdDataTableTemplate="menu" let-row="row" let-index="index">
+        <div layout="row" layout-align="end center">
+          <button md-icon-button (click)="edit(row.id)" color="primary"><md-icon>edit</md-icon></button>
+          <button md-icon-button (click)="delete(row)" color="warn"><md-icon>delete</md-icon></button>
+        </div>
+      </template>
+    </td-data-table>
+    <td-paging-bar #pagingBar [pageSizes]="[10, 20, 40]" [total]="filteredTotal" (change)="page($event)" [hidden]="pagingBar.total <= 10">
+      <span td-paging-bar-label hide-xs>Rows per page:</span> {{pagingBar.range}} <span hide-xs>of {{pagingBar.total}}</span>
+    </td-paging-bar>
+  </div>
+</td-layout-card-over>
diff --git a/securis/src/main/webapp/src/app/listing/application.list.component.ts b/securis/src/main/webapp/src/app/listing/application.list.component.ts
new file mode 100644
index 0000000..5ebeb39
--- /dev/null
+++ b/securis/src/main/webapp/src/app/listing/application.list.component.ts
@@ -0,0 +1,89 @@
+import { Router, ActivatedRoute } from '@angular/router';
+import { MdDialog, MdDialogConfig } from '@angular/material';
+import {
+    ITdDataTableColumn,
+    ITdDataTableSortChangeEvent,
+    TdDataTableService,
+    TdDataTableSortingOrder,
+    TdPagingBarComponent
+} from '@covalent/core';
+import { IPageChangeEvent } from '@covalent/core';
+import { Component, ViewChild, AfterViewInit } from '@angular/core';
+import { TdMediaService } from '@covalent/core';
+import { ApplicationsService } from '../resources/applications';
+import { PackFormComponent } from '../forms/pack.form.component';
+import { LocaleService } from '../common/i18n';
+import { ListingBase } from './base';
+
+
+var app_example = { 
+	code: 'CICS',
+  creation_timestamp: 1418384439000,
+  description: 'Wellbore integrity analysis software',
+  id: 1,
+  license_filename: 'config_server.lic',
+  name: 'CurisIntegrity',
+  metadata: 
+   [ { key: 'max_docs',
+       value: '250000',
+       readonly: true,
+       mandatory: true } ] 
+}
+
+@Component({
+  selector: 'application-list',
+  templateUrl: 'src/app/listing/application.list.component.html'
+})
+export class ApplicationListComponent extends ListingBase implements AfterViewInit {
+
+  columns: ITdDataTableColumn[] = [
+    { name: 'code', label: 'Code', tooltip: 'Application code' },
+    { name: 'name', label: 'Application name' },
+    { name: 'creation_timestamp', label: 'Creation date' },
+    { name: 'menu', label: '' }
+  ];
+
+  pack_menu_options : any[] = [{
+    command: 'edit',
+    name: 'Edit'
+  },{
+    command: 'cancel',
+    name: 'Cancel'
+  }]
+  
+
+  constructor(_dataTableService: TdDataTableService,
+    private media: TdMediaService,
+    private router: Router,
+    private $L: LocaleService,
+    private applicationForm: PackFormComponent,
+    private applications: ApplicationsService) {
+      super(_dataTableService);
+      this.applications.get().subscribe(
+        (list : any[]) => {
+          this.data = list;
+          this.refresh();
+        },
+        (err: any) => console.error(err)
+      );
+  }
+
+
+  packAction(action: any) {
+    console.log(action.command);
+  }
+
+  isActionAvailable(pack : any) : boolean {
+    return true;
+  }
+
+  create() : void {
+    this.router.navigate(['applications/create']);
+  }
+
+  edit(appId: number | string) : void {
+    this.router.navigate([`applications/edit/${appId}`]);
+  }
+
+}
+
diff --git a/securis/src/main/webapp/src/app/listing/base.ts b/securis/src/main/webapp/src/app/listing/base.ts
new file mode 100644
index 0000000..8ae3483
--- /dev/null
+++ b/securis/src/main/webapp/src/app/listing/base.ts
@@ -0,0 +1,83 @@
+import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
+import { TdDataTableService, TdPagingBarComponent, TdDataTableSortingOrder, IPageChangeEvent, ITdDataTableSortChangeEvent } from '@covalent/core';
+import { UserService } from '../user.service';
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
+
+export interface IListing {
+
+	create() : void;
+	edit(id: number | string) : void;
+	refresh() : void;
+	sort(sortEvent: ITdDataTableSortChangeEvent): void;
+	search(searchTerm: string): void;
+	page(pagingEvent: IPageChangeEvent): void;
+}
+
+export class ListingBase implements IListing, AfterViewInit {
+  data: any[] = [];
+  
+  @ViewChild('pagingBar') pagingBar : TdPagingBarComponent ;
+  filteredData: any[] = this.data;
+  filteredTotal: number = this.data.length;
+  
+  searchTerm: string = '';
+  fromRow: number = 1;
+  currentPage: number = 1;
+  pageSize: number = 10;
+  sortBy: string;
+  sortOrder: TdDataTableSortingOrder = TdDataTableSortingOrder.Descending;
+  filteredItems = this.data.length;
+  
+  constructor(private _dataTableService: TdDataTableService) {
+  }
+
+  create() : void {
+    // To be implemented in the child class
+    // For instance: 
+    // this.router.navigate([`create`], {relativeTo: this.route});
+    throw new Error('Method not implemented');
+  }
+
+  edit(id: number | string) : void {
+    // To be implemented in the child class
+    // For instance: 
+    // this.router.navigate([`edit/${id}`], {relativeTo: this.route});
+    throw new Error('Method not implemented');
+  }
+
+
+  sort(sortEvent: ITdDataTableSortChangeEvent): void {
+    this.sortBy = sortEvent.name;
+    this.sortOrder = sortEvent.order;
+    this.refresh();
+  }
+
+  search(searchTerm: string): void {
+    this.searchTerm = searchTerm;
+    this.refresh();
+  }
+
+  page(pagingEvent: IPageChangeEvent): void {
+    this.fromRow = pagingEvent.fromRow;
+    this.currentPage = pagingEvent.page;
+    this.pageSize = pagingEvent.pageSize;
+    this.refresh();
+  }
+
+
+  refresh(): void {
+    let newData: any[] = this.data;
+    newData = this._dataTableService.filterData(newData, this.searchTerm, true);
+    this.filteredTotal = newData.length;
+    this.filteredItems = newData.length;
+    newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder);
+    newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize);
+    this.filteredData = newData;
+  }
+
+  ngAfterViewInit(): void {
+    this.refresh();
+  }
+
+  
+}
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/license.list.component.html b/securis/src/main/webapp/src/app/listing/license.list.component.html
similarity index 81%
rename from securis/src/main/webapp/src/app/license.list.component.html
rename to securis/src/main/webapp/src/app/listing/license.list.component.html
index 7a33cfd..70f72d1 100644
--- a/securis/src/main/webapp/src/app/license.list.component.html
+++ b/securis/src/main/webapp/src/app/listing/license.list.component.html
@@ -11,15 +11,19 @@
     </span>
     <td-search-box #searchBox class="push-right-sm" placeholder="Search here" (searchDebounce)="search($event)" flex>
     </td-search-box>
-    <button md-mini-fab color="accent" (click)="createLicense()">
-        <md-icon>add</md-icon>
+    <button md-mini-fab color="accent" (click)="create()" [mdTooltip]="$L.get('Create a new license')">
+        <md-icon>add</md-icon>        
       </button>
     <md-toolbar-row *ngIf="!!pack">
-      <md-chip-list flex="80" style="margin-left: 70px;">
+      <md-chip-list flex="70" style="margin-left: 70px;">
         <md-chip selected [mdTooltip]="$L.get('field.application_name')" color="primary">{{pack.application_name}} </md-chip>
         <md-chip selected [mdTooltip]="$L.get('field.organization_id')" color="accent">{{pack.organization_name}} </md-chip>
         <md-chip selected [mdTooltip]="$L.get('field.license_type_id')" color="accent">{{pack.licensetype_code}} </md-chip>
-        <md-chip selected [mdTooltip]="$L.get('field.num_available')" color="accent">{{pack.num_available}} </md-chip>
+      </md-chip-list>
+      <span flex></span>
+      <md-chip-list>
+        <md-chip [mdTooltip]="$L.get('field.num_available')" color="secondary" [class.bgc-red-A100]="pack.num_available <= 0">
+          <span i18n="field.num_available"></span>: {{pack.num_available}} </md-chip>
       </md-chip-list>
     </md-toolbar-row>
   </md-toolbar>
@@ -54,7 +58,7 @@
       
       <template tdDataTableTemplate="menu" let-row="row" let-index="index">
         <div layout="row" layout-align="end center">
-          <button md-icon-button (click)="editLicense(row)" color="primary"><md-icon>edit</md-icon></button>
+          <button md-icon-button (click)="edit(row.id)" color="primary"><md-icon>edit</md-icon></button>
           <button md-icon-button [mdMenuTriggerFor]="licenseMenu" aria-label="License menu">
             <md-icon>more_vert</md-icon>
           </button>
@@ -66,7 +70,7 @@
         </div>
       </template>
     </td-data-table>
-    <td-paging-bar #pagingBar [pageSizes]="[10, 20, 40]" [total]="filteredTotal" (change)="page($event)" [hidden]="pagingBar.total <= 10" >
+    <td-paging-bar #pagingBar [pageSizes]="[10, 25, 50, 100]" [total]="filteredTotal" (change)="page($event)" [hidden]="pagingBar.total <= 10" >
       <span i18n td-paging-bar-label hide-xs>Rows per page:</span> {{pagingBar.range}} <span hide-xs>of {{pagingBar.total}}</span>
     </td-paging-bar>
   </div>
diff --git a/securis/src/main/webapp/src/app/listing/license.list.component.ts b/securis/src/main/webapp/src/app/listing/license.list.component.ts
new file mode 100644
index 0000000..4783054
--- /dev/null
+++ b/securis/src/main/webapp/src/app/listing/license.list.component.ts
@@ -0,0 +1,117 @@
+import { ActivatedRoute, Router } from '@angular/router';
+import { MdDialog, MdDialogConfig } from '@angular/material';
+import { TdDataTableService, TdPagingBarComponent, TdDataTableSortingOrder, ITdDataTableSortChangeEvent, ITdDataTableColumn } from '@covalent/core';
+import { IPageChangeEvent } from '@covalent/core';
+import { Component, AfterViewInit, ViewChild } from '@angular/core';
+import { TdMediaService } from '@covalent/core';
+import { Location } from '@angular/common';
+
+import { LocaleService } from '../common/i18n';
+import { LicensesService } from '../resources/licenses';
+import { PacksService } from '../resources/packs';
+import { LicenseFormComponent } from '../forms/license.form.component';
+import { ListingBase } from './base';
+
+var lic_example = { activation_code: '19fa8d30-29cb-4b59-81b5-3837af8204b6',
+  code: 'CISA02-494-1',
+  code_suffix: 1,
+  created_by_id: '_client',
+  creation_timestamp: 1447848747000,
+  email: 'ccalvo@curisit.net',
+  expiration_date: 1450440747000,
+  full_name: 'César SA',
+  id: 110,
+  licenseData: '{"appCode":"CISA","appName":"CurisIntegrity SA","licenseCode":"CISA02-494-1","activationCode":"19fa8d30-29cb-4b59-81b5-3837af8204b6","expirationDate":1450440746790,"arch":"x86_64","osName":"Mac OS X","macAddresses":["60-03-08-95-AE-D0","B6-2B-33-E9-64-2D"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f","metadata":{"maxWellLifeLines":"50","simulationModes":"A1,A2,N1,QL"},"signature":"Tejun4bNbknxOyEmPaO/fGfGhv4URhVON/7bESxbODFWMJYKQqOPHrDiSUMlf6RbfWSVg2Dry8bY1WX881QGjTkBaHeDJKCy1EaJBwJ2nv9TYSMOiRj0eqMNYWE9/oLpvufHylAkPUpZwXVkSzTxmN+RvWa2Xt4Fu7xN+4PDHV4t7PSq7QwsFlD9ArgYC6Vx+zuL9WZANBtJ2gU/gKOE0CU0KjsB49RGQSFS/G27+H/YuDkCiQq7PC7VdVwYONQ2HO91fyPvInIrzDC5+sWHcUAqSCop//8klMy03hWl6VvAlaSP7kNM3KadyqXIJ3tx4Jwm1W+gBb3tngHzVCpYmw=="}',
+  modification_timestamp: 1447848747000,
+  pack_code: 'CISA02',
+  pack_id: 18,
+  request_data: '{"appCode":"CISA","activationCode":"19fa8d30-29cb-4b59-81b5-3837af8204b6","arch":"x86_64","osName":"Mac OS X","macAddresses":["60-03-08-95-AE-D0","B6-2B-33-E9-64-2D"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f"}',
+  status: 'AC' }
+
+@Component({
+  selector: 'license-list',
+  templateUrl: 'src/app/listing/license.list.component.html'
+})
+export class LicenseListComponent extends ListingBase implements AfterViewInit {
+  pack: any = null;
+  columns: ITdDataTableColumn[] = [
+    { name: 'code', label: 'Code', tooltip: 'License code' },
+    { name: 'full_name', label: 'User name' },
+    { name: 'email', label: 'User email' },
+    { name: 'expiration_date', label: 'Expiration date' },
+    { name: 'status', label: 'Status' },
+    { name: 'menu', label: '' }
+  ];
+
+  license_menu_options : any[] = [{
+    icon: 'edit',
+    command: 'edit',
+    name: 'Edit'
+  },{
+    icon: 'cancel',
+    command: 'cancel',
+    name: 'Cancel'
+  }]
+  
+  licenseAction(action: any) {
+    console.log(action.command);
+  }
+
+  isActionAvailable(pack : any) : boolean {
+    return true;
+  }
+
+  constructor( _dataTableService: TdDataTableService,
+    private media: TdMediaService,
+    private $L: LocaleService,
+    private router: Router,
+    private location: Location,
+    private route: ActivatedRoute,
+    private dialog: MdDialog,
+    private licenseForm: LicenseFormComponent,
+    private licenses: LicensesService,
+    private packs: PacksService) {
+      super(_dataTableService);
+  }
+
+  ngOnInit(): void {
+    this.route.params.subscribe(params => {
+        var packId = +params['packId']; // (+) converts string 'id' to a number
+        this.licenses.getByPack(packId).subscribe(
+          list => {
+            this.data = list;
+            this.refresh();
+          },
+          err => console.error(err)
+        );
+        this.packs.get(packId).subscribe(
+          packData => {
+            this.pack = packData;
+          },
+          err => console.error(err)
+        );
+      });
+  }
+
+  goBack() : void {
+    this.router.navigate([`packs`]);
+  }
+
+  isLicenseExpired(lic: any): boolean {
+    return lic.expiration_date < (new Date().getTime());
+  }
+
+  create() : void {
+    this.router.navigate([`packs/${this.pack.id}/licenses/create`]);
+  }
+
+  edit(licId: number | string) : void {
+    this.router.navigate([`packs/${this.pack.id}/licenses/edit/${licId}`]);
+  }
+
+  ngAfterViewInit(): void {
+    this.media.broadcast();
+
+  }
+}
+
diff --git a/securis/src/main/webapp/src/app/pack.list.component.html b/securis/src/main/webapp/src/app/listing/pack.list.component.html
similarity index 92%
rename from securis/src/main/webapp/src/app/pack.list.component.html
rename to securis/src/main/webapp/src/app/listing/pack.list.component.html
index 7e2a344..0399351 100644
--- a/securis/src/main/webapp/src/app/pack.list.component.html
+++ b/securis/src/main/webapp/src/app/listing/pack.list.component.html
@@ -8,7 +8,7 @@
     </span>
     <td-search-box #searchBox class="push-right-sm" placeholder="Search here" (searchDebounce)="search($event)" flex>
     </td-search-box>
-    <button md-mini-fab color="accent" (click)="createPack()">
+    <button md-mini-fab color="accent" (click)="create()" [mdTooltip]="$L.get('Create a new pack')">
         <md-icon>add</md-icon>
       </button>
   </md-toolbar>
@@ -35,7 +35,7 @@
       </template>
       <template tdDataTableTemplate="menu" let-row="row" let-index="index">
         <div layout="row" layout-align="end center">
-          <button md-icon-button (click)="editPack(row)" color="primary"><md-icon>edit</md-icon></button>
+          <button md-icon-button (click)="edit(row.id)" color="primary"><md-icon>edit</md-icon></button>
           <button md-icon-button [mdMenuTriggerFor]="packMenu" aria-label="Pack menu">
             <md-icon>more_vert</md-icon>
           </button>
diff --git a/securis/src/main/webapp/src/app/listing/pack.list.component.ts b/securis/src/main/webapp/src/app/listing/pack.list.component.ts
new file mode 100644
index 0000000..d359e7a
--- /dev/null
+++ b/securis/src/main/webapp/src/app/listing/pack.list.component.ts
@@ -0,0 +1,122 @@
+import { Router, ActivatedRoute } from '@angular/router';
+import { MdDialog, MdDialogConfig } from '@angular/material';
+import {
+    ITdDataTableColumn,
+    ITdDataTableSortChangeEvent,
+    TdDataTableService,
+    TdDataTableSortingOrder,
+    TdPagingBarComponent
+} from '@covalent/core';
+import { IPageChangeEvent } from '@covalent/core';
+import { Component, ViewChild, AfterViewInit } from '@angular/core';
+import { TdMediaService } from '@covalent/core';
+import { PacksService } from '../resources/packs';
+import { PackFormComponent } from '../forms/pack.form.component';
+import { LocaleService } from '../common/i18n';
+import { ListingBase } from './base';
+
+
+var pack_example = { 
+  id: 7,
+  code: 'DX250000',
+  status: 'AC',
+  application_name: 'Doxr',
+  created_by_id: 'admin',
+  created_by_name: 'Administrator  (admin)',
+  creation_timestamp: 1440597540000,
+  end_valid_date: 2051222400000,
+  init_valid_date: 1440547200000,
+  license_preactivation: true,
+  license_type_id: 5,
+  licensetype_code: 'DXL3',
+  metadata: 
+   [ { key: 'max_docs',
+       value: '250000',
+       readonly: true,
+       mandatory: true,
+       pack_id: 7 } ],
+  num_activations: 7,
+  num_available: -2,
+  num_creations: 7,
+  num_licenses: 5,
+  organization_id: 2,
+  organization_name: 'CurisTec',
+  preactivation_valid_period: 70,
+  renew_valid_period: 0,
+}
+
+@Component({
+  selector: 'pack-list',
+  templateUrl: 'src/app/listing/pack.list.component.html'
+})
+export class PackListComponent extends ListingBase implements AfterViewInit {
+
+  columns: ITdDataTableColumn[] = [
+    { name: 'code', label: 'Code', tooltip: 'License pack code' },
+    { name: 'application_name', label: 'App name' },
+    { name: 'licensetype_code', label: 'License type' },
+    { name: 'organization_name', label: 'Organization' },
+    { name: 'used_licenses', label: 'Licenses', tooltip: 'Initial/Available pack licenses' },
+    { name: 'menu', label: '' }
+  ];
+
+  pack_menu_options : any[] = [{
+    command: 'edit',
+    name: 'Edit'
+  },{
+    command: 'cancel',
+    name: 'Cancel'
+  }]
+  
+
+  constructor(_dataTableService: TdDataTableService,
+    private media: TdMediaService,
+    private router: Router,
+    private route: ActivatedRoute,
+    private dialog: MdDialog,
+    private $L: LocaleService,
+    private packForm: PackFormComponent,
+    private packs: PacksService) {
+      super(_dataTableService);
+      this.packs.get().subscribe(
+        (list : any[]) => {
+          this.data = list;
+          this.refresh();
+        },
+        (err: any) => console.error(err)
+      );
+  }
+
+
+  packAction(action: any) {
+    console.log(action.command);
+  }
+
+  isActionAvailable(pack : any) : boolean {
+    return true;
+  }
+
+  showLicenses(pack: any) : void {
+    this.router.navigate([`${pack.id}/licenses`], {relativeTo: this.route});
+  }
+
+  create() : void {
+    this.router.navigate([`create`], {relativeTo: this.route});
+  }
+
+  edit(pack: any) : void {
+    this.router.navigate([`edit/${pack.id}`], {relativeTo: this.route});
+  }
+
+  sort(sortEvent: ITdDataTableSortChangeEvent): void {
+    this.sortBy = sortEvent.name === 'used_licenses' ? 'num_available' : sortEvent.name;
+    this.sortOrder = sortEvent.order;
+    this.refresh();
+  }
+
+  ngAfterViewInit(): void {
+    this.media.broadcast();
+
+  }
+}
+
diff --git a/securis/src/main/webapp/src/app/menu.component.html b/securis/src/main/webapp/src/app/menu.component.html
index 6cc9d20..d367da1 100644
--- a/securis/src/main/webapp/src/app/menu.component.html
+++ b/securis/src/main/webapp/src/app/menu.component.html
@@ -3,28 +3,28 @@
   </td-navigation-drawer>
 
   <md-nav-list td-sidenav-content>
-    <a routerLink="/menu/packs" md-list-item (click)="closeMenu()">
-      <md-icon md-list-avatar>view_compact</md-icon>
+    <a routerLink="/packs" md-list-item (click)="closeMenu()">
+      <md-icon md-list-avatar>collections_bookmark</md-icon>
       <h3 md-line i18n="menu.packs">  </h3>
       <p md-line i18n="menu.packs.description"> </p>
     </a>
-    <a routerLink="/menu/packs" md-list-item (click)="closeMenu()">
-      <md-icon md-list-avatar>view_compact</md-icon>
+    <a routerLink="/applications" md-list-item (click)="closeMenu()">
+      <md-icon md-list-avatar>web</md-icon>
       <h3 md-line i18n="menu.applications">  </h3>
       <p md-line i18n="menu.applications.description"> </p>
     </a>
-    <a routerLink="/menu/packs" md-list-item (click)="closeMenu()">
-      <md-icon md-list-avatar>view_compact</md-icon>
+    <a routerLink="licesetypes" md-list-item (click)="closeMenu()">
+      <md-icon md-list-avatar>class</md-icon>
       <h3 md-line i18n="menu.license_types">  </h3>
       <p md-line i18n="menu.license_types.description"> </p>
     </a>
-    <a routerLink="/menu/packs" md-list-item (click)="closeMenu()">
-      <md-icon md-list-avatar>view_compact</md-icon>
+    <a routerLink="organizations" md-list-item (click)="closeMenu()">
+      <md-icon md-list-avatar>business</md-icon>
       <h3 md-line i18n="menu.organizations">  </h3>
       <p md-line i18n="menu.organizations.description"> </p>
     </a>
-    <a routerLink="/menu/packs" md-list-item (click)="closeMenu()">
-      <md-icon md-list-avatar>view_compact</md-icon>
+    <a routerLink="users" md-list-item (click)="closeMenu()">
+      <md-icon md-list-avatar>account_circle</md-icon>
       <h3 md-line i18n="menu.users">  </h3>
       <p md-line i18n="menu.users.description"> </p>
     </a>                
@@ -33,8 +33,11 @@
 <td-layout-nav toolbarTitle="SeCuris" logo="assets:logo-white">
   <div td-toolbar-content layout="row" layout-align="start center" flex>
     <span flex ></span>
-    <button md-icon-button (click)="logout()">
-        <md-icon color="white">exit_to_app</md-icon>
+    <md-icon>account_box</md-icon>
+    <span>&nbsp;{{userFullName}}</span>
+    <span flex="5" ></span>
+    <button md-mini-fab raised (click)="logout()" color="warn" [mdTooltip]="$L.get('Logout')">
+        <md-icon>exit_to_app</md-icon>
     </button>
   </div>
 	<router-outlet></router-outlet>
diff --git a/securis/src/main/webapp/src/app/menu.component.ts b/securis/src/main/webapp/src/app/menu.component.ts
index 0e5cd83..8866068 100644
--- a/securis/src/main/webapp/src/app/menu.component.ts
+++ b/securis/src/main/webapp/src/app/menu.component.ts
@@ -1,8 +1,10 @@
+import { LocaleService } from './common/i18n';
+import { LocalStorageService } from 'angular-2-local-storage';
 import { Observable } from 'rxjs/Observable';
 import { BaseRequestOptions, Http } from '@angular/http';
 import { Component, ViewChild } from '@angular/core';
 import { UserService } from './user.service';
-import { Router } from '@angular/router';
+import { ActivatedRoute, Router } from '@angular/router';
 import { TdNavigationDrawerComponent } from '@covalent/core'
 
 
@@ -13,8 +15,12 @@
 
   @ViewChild('mainMenu') mainMenu: TdNavigationDrawerComponent;
 
+  userFullName: string;
 
   constructor(private userService: UserService,
+              private store: LocalStorageService,
+              private $L: LocaleService,
+              private route: ActivatedRoute,
               private router: Router) {
   }
 
@@ -23,8 +29,12 @@
         let isLoggedIn = authOk.valueOf();
         if (!isLoggedIn) {
           this.router.navigateByUrl('public/login');
+          this.userFullName = null;
         } else {
-          this.router.navigate(['packs']);
+          if (this.route.firstChild == null) {
+            this.router.navigate(['packs']);
+          }
+          this.userFullName = this.store.get<string>("user_full_name");
         }
       }  , 
       err => /* Show message */ this.router.navigateByUrl('public/login'));  
diff --git a/securis/src/main/webapp/src/app/pack.list.component.ts b/securis/src/main/webapp/src/app/pack.list.component.ts
deleted file mode 100644
index e13800b..0000000
--- a/securis/src/main/webapp/src/app/pack.list.component.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Router, ActivatedRoute } from '@angular/router';
-import { MdDialog, MdDialogConfig } from '@angular/material';
-import {
-    ITdDataTableColumn,
-    ITdDataTableSortChangeEvent,
-    TdDataTableService,
-    TdDataTableSortingOrder,
-    TdPagingBarComponent
-} from '@covalent/core';
-import { IPageChangeEvent } from '@covalent/core';
-import { Component, ViewChild, AfterViewInit } from '@angular/core';
-import { TdMediaService } from '@covalent/core';
-import { PacksService } from './resources/packs';
-import { PackFormComponent } from './forms/pack.form.component';
-import { LocaleService } from './common/i18n';
-
-
-var pack_example = { 
-  id: 7,
-  code: 'DX250000',
-  status: 'AC',
-  application_name: 'Doxr',
-  created_by_id: 'admin',
-  created_by_name: 'Administrator  (admin)',
-  creation_timestamp: 1440597540000,
-  end_valid_date: 2051222400000,
-  init_valid_date: 1440547200000,
-  license_preactivation: true,
-  license_type_id: 5,
-  licensetype_code: 'DXL3',
-  metadata: 
-   [ { key: 'max_docs',
-       value: '250000',
-       readonly: true,
-       mandatory: true,
-       pack_id: 7 } ],
-  num_activations: 7,
-  num_available: -2,
-  num_creations: 7,
-  num_licenses: 5,
-  organization_id: 2,
-  organization_name: 'CurisTec',
-  preactivation_valid_period: 70,
-  renew_valid_period: 0,
-}
-
-const DIALOG_OPTIONS : MdDialogConfig = {
-  height: '80%', // can be px or %
-  width: '45%', // can be px or %
-}
-
-@Component({
-  selector: 'pack-list',
-  templateUrl: 'src/app/pack.list.component.html'
-})
-export class PackListComponent implements AfterViewInit {
-  data: any[] = [];
-  
-  @ViewChild('pagingBar') pagingBar : TdPagingBarComponent ;
-
-  columns: ITdDataTableColumn[] = [
-    { name: 'code', label: 'Code', tooltip: 'License pack code' },
-    { name: 'application_name', label: 'App name' },
-    { name: 'licensetype_code', label: 'License type' },
-    { name: 'organization_name', label: 'Organization' },
-    { name: 'used_licenses', label: 'Licenses', tooltip: 'Initial/Available pack licenses' },
-    { name: 'menu', label: '' }
-  ];
-
-  filteredData: any[] = this.data;
-  filteredTotal: number = this.data.length;
-
-  searchTerm: string = '';
-  fromRow: number = 1;
-  currentPage: number = 1;
-  pageSize: number = 10;
-  sortBy: string = 'code';
-  sortOrder: TdDataTableSortingOrder = TdDataTableSortingOrder.Descending;
-  filteredItems = this.data.length;
-  pack_menu_options : any[] = [{
-    command: 'edit',
-    name: 'Edit'
-  },{
-    command: 'cancel',
-    name: 'Cancel'
-  }]
-  
-  packAction(action: any) {
-    console.log(action.command);
-  }
-
-  isActionAvailable(pack : any) : boolean {
-    return true;
-  }
-
-  constructor(private _dataTableService: TdDataTableService,
-    private media: TdMediaService,
-    private router: Router,
-    private route: ActivatedRoute,
-    private dialog: MdDialog,
-    private $L: LocaleService,
-    private packForm: PackFormComponent,
-    private packs: PacksService) {
-      this.packs.get().subscribe(
-        list => {
-          this.data = list;
-          this.filter();
-        },
-        err => console.error(err)
-      );
-  }
-
-  ngOnInit(): void {
-    this.filter();
-  }
-
-  createPack() : void {
-    var ref = this.dialog.open(PackFormComponent, DIALOG_OPTIONS);
-    ref.componentInstance.isNew = true;
-    ref.afterClosed().subscribe(result => {
-      console.log(result);
-      this.filter();
-    });
-  }
-
-  showLicenses(pack: any) : void {
-    this.router.navigate([`${pack.id}/licenses`], {relativeTo: this.route});
-  }
-
-  editPack(pack: any) : void {
-    var ref = this.dialog.open(PackFormComponent, DIALOG_OPTIONS);
-    ref.componentInstance.isNew = false;
-    ref.componentInstance.data = pack;
-    ref.afterClosed().subscribe(result => {
-      console.log(result);
-      this.filter();
-    });
-  }
-
-
-  sort(sortEvent: ITdDataTableSortChangeEvent): void {
-    this.sortBy = sortEvent.name === 'used_licenses' ? 'num_available' : sortEvent.name;
-    this.sortOrder = sortEvent.order;
-    this.filter();
-    console.log(this.pagingBar);
-  }
-
-  search(searchTerm: string): void {
-    this.searchTerm = searchTerm;
-    this.filter();
-  }
-
-  page(pagingEvent: IPageChangeEvent): void {
-    this.fromRow = pagingEvent.fromRow;
-    this.currentPage = pagingEvent.page;
-    this.pageSize = pagingEvent.pageSize;
-    this.filter();
-  }
-
-  loadData() {
-
-  }
-
-  filter(): void {
-    let newData: any[] = this.data;
-    newData = this._dataTableService.filterData(newData, this.searchTerm, true);
-    this.filteredTotal = newData.length;
-    this.filteredItems = newData.length;
-    newData = this._dataTableService.sortData(newData, this.sortBy, this.sortOrder);
-    newData = this._dataTableService.pageData(newData, this.fromRow, this.currentPage * this.pageSize);
-    this.filteredData = newData;
-  }
-
-  ngAfterViewInit(): void {
-    this.media.broadcast();
-
-  }
-}
-
diff --git a/securis/src/main/webapp/src/app/resources/packs.ts b/securis/src/main/webapp/src/app/resources/packs.ts
index 6da7c06..f92292f 100644
--- a/securis/src/main/webapp/src/app/resources/packs.ts
+++ b/securis/src/main/webapp/src/app/resources/packs.ts
@@ -75,6 +75,11 @@
   public putonhold(id: number) {
 			return super.action(id, "putonhold");
 	}
+  public nextLicCode(id: number) {
+      let url = `pack/${id}/next_license_code`
+      return this.http.get(url).map(response => response.text());
+	}
+  
 
  	public isActionAvailable(action:string, pack:any) {
 		var validStatuses = PACK_ACTIONS_BY_STATUS[action];
diff --git a/securis/src/main/webapp/src/app/user.service.ts b/securis/src/main/webapp/src/app/user.service.ts
index e4dac43..a0656a7 100644
--- a/securis/src/main/webapp/src/app/user.service.ts
+++ b/securis/src/main/webapp/src/app/user.service.ts
@@ -28,11 +28,12 @@
     let options = new RequestOptions({ headers: new Headers({ "Content-Type": "application/x-www-form-urlencoded" })});
     return this.http.post('user/login', params.toString(), options)
                     .map((resp) => this.mapLogin(resp))
-                    .catch(this.handleError);
+                    .catch((err) => this.handleError(err));
   }
 
   private mapLogin(res : Response) : string {
     let data = res.json();
+    this.store.set('user_full_name', data.full_name);
     this.store.set('username', data.username);
 		this.store.set('token', data.token);
     return <string>data.token;
@@ -46,7 +47,7 @@
     let option = new RequestOptions({ headers: new Headers({ 'X-SECURIS-TOKEN': token }) });
     return this.http.get('check', option)
                     .map((resp) => this.mapCheck(resp))
-                    .catch(this.handleError);
+                    .catch((err) => this.handleError(err));
   }
 
   private mapCheck(res : Response) : boolean {
diff --git a/securis/src/main/webapp/src/lang/messages_en.json b/securis/src/main/webapp/src/lang/messages_en.json
index a50b002..bb03671 100644
--- a/securis/src/main/webapp/src/lang/messages_en.json
+++ b/securis/src/main/webapp/src/lang/messages_en.json
@@ -14,10 +14,17 @@
 	"field.preactivation_valid_period": "Preactivation valid period",
 	"field.renew_valid_period": "Renew valid period",
 	"field.application_name": "Application name",
+	"field.activation_code": "Activation code",
 	"field.status": "Status",
 	"field.metadata": "Metadata",
 	"field.key": "Parameter",
 	"field.value": "Value",
+	"field.created_by": "Created by",
+	"field.creation_date": "Creation date",
+	"field.request_data": "Request data",
+	"field.full_name": "Full name",
+	"field.email": "Email",
+	"field.creation_timestamp": "Creation timestamp",
 	"field.comments": "Comments",
 	"pack.status.CR": "Created",
 	"pack.status.AC": "Active",

--
Gitblit v1.3.2