From 38b0782c887f046426c31766901906c614d73140 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Tue, 14 Mar 2017 13:51:56 +0000
Subject: [PATCH] #3527 feature - Added pack form
---
securis/src/main/webapp/src/app/license.list.component.ts | 151 ++++++++++
securis/src/main/webapp/src/app/pack.list.component.html | 37 +
securis/src/main/webapp/src/app/license.list.component.html | 51 +++
securis/src/main/webapp/src/app/common/session.ts | 30 ++
securis/src/main/java/net/curisit/securis/DevFilter.java | 2
securis/src/main/webapp/src/app/common/i18n.ts | 20
securis/src/main/webapp/src/app/common/error.checker.ts | 55 +++
securis/src/main/webapp/src/app/common/default.requests.options.ts | 4
securis/src/main/webapp/src/app/forms/pack.form.component.ts | 69 ++++
securis/src/main/webapp/src/app/app.module.ts | 6
securis/src/main/webapp/src/app/forms/license.form.component.ts | 53 +++
securis/src/main/webapp/src/app/forms/pack.form.html | 229 ++++++++++----
securis/src/main/webapp/src/app/pack.list.component.ts | 24 +
securis/src/main/webapp/assets/securis.css | 13
securis/src/main/webapp/src/app/forms/license.form.html | 75 +++++
securis/src/main/webapp/src/lang/messages_en.json | 22 +
16 files changed, 739 insertions(+), 102 deletions(-)
diff --git a/securis/src/main/java/net/curisit/securis/DevFilter.java b/securis/src/main/java/net/curisit/securis/DevFilter.java
index 2a3c6c0..8b01f33 100644
--- a/securis/src/main/java/net/curisit/securis/DevFilter.java
+++ b/securis/src/main/java/net/curisit/securis/DevFilter.java
@@ -37,7 +37,7 @@
res.addHeader("Access-Control-Allow-Headers", "X-SECURIS-TOKEN, Content-Type");
res.addHeader("Access-Control-Expose-Headers", "X-SECURIS-ERROR-MSG, X-SECURIS-ERROR-CODE, Content-Type");
- LOG.info("Added header to: " + res.getHeaderNames());
+ // LOG.info("Added header to: " + res.getHeaderNames());
if (!req.getMethod().equals("OPTIONS")) {
fc.doFilter(sreq, sres);
}
diff --git a/securis/src/main/webapp/assets/securis.css b/securis/src/main/webapp/assets/securis.css
index 993196c..64749e5 100644
--- a/securis/src/main/webapp/assets/securis.css
+++ b/securis/src/main/webapp/assets/securis.css
@@ -28,4 +28,17 @@
.td-data-table-row > .td-data-table-cell:first-child,
.td-data-table-row > .td-data-table-column:first-child {
max-width: 30px !important;
+}
+
+md-dialog-actions > .mat-button {
+ margin-left: 5px !important;
+ margin-right: 5px !important;
+}
+
+.label-value {
+ margin-top: 20px;
+}
+
+input:read-only {
+ color: rgba(0, 0, 0, 0.50) !important;
}
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/app.module.ts b/securis/src/main/webapp/src/app/app.module.ts
index 04dca82..9b3ec9d 100644
--- a/securis/src/main/webapp/src/app/app.module.ts
+++ b/securis/src/main/webapp/src/app/app.module.ts
@@ -1,3 +1,4 @@
+import { ErrorCheckerComponent } from './common/error.checker';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
@@ -11,6 +12,7 @@
import { ToastModule } from 'ng2-toastr/ng2-toastr';
import { AppHomeComponent } from './app.component';
+import { I18nDirective } from './common/i18n';
import { UserService } from './user.service';
import { PacksService } from './resources/packs';
import { LicenseTypesService } from './resources/license_types';
@@ -25,6 +27,7 @@
import { appRoutes, appRoutingProviders } from './app.routes';
import { requestOptionsProvider, requestBackendProvider } from './common/default.requests.options';
import { LocaleServiceModule } from './common/i18n';
+import { SeCurisSession } from './common/session';
import { PackFormComponent } from "./forms/pack.form.component";
@NgModule({
@@ -48,11 +51,14 @@
PackListComponent,
PackFormComponent,
LoginFormComponent,
+ ErrorCheckerComponent,
+ I18nDirective,
AppHomeComponent
],
bootstrap: [ AppHomeComponent ],
entryComponents: [ PackFormComponent ],
providers: [
+ SeCurisSession,
UserService,
PacksService,
LicensesService,
diff --git a/securis/src/main/webapp/src/app/common/default.requests.options.ts b/securis/src/main/webapp/src/app/common/default.requests.options.ts
index d02c654..5b3cba2 100644
--- a/securis/src/main/webapp/src/app/common/default.requests.options.ts
+++ b/securis/src/main/webapp/src/app/common/default.requests.options.ts
@@ -31,7 +31,7 @@
}
}
-
+
@Injectable()
export class ApiXHRBackend extends XHRBackend {
@@ -40,7 +40,7 @@
}
createConnection(request: Request): XHRConnection {
- if (!request.url.endsWith('.js') && !request.url.endsWith('.html') && !request.url.endsWith('.svg')){
+ if (!request.url.endsWith('.js') && !request.url.endsWith('.json') && !request.url.endsWith('.html') && !request.url.endsWith('.svg')){
request.url = 'http://localhost:8080/securis/' + request.url; // prefix base url
}
return super.createConnection(request);
diff --git a/securis/src/main/webapp/src/app/common/error.checker.ts b/securis/src/main/webapp/src/app/common/error.checker.ts
new file mode 100644
index 0000000..b08055e
--- /dev/null
+++ b/securis/src/main/webapp/src/app/common/error.checker.ts
@@ -0,0 +1,55 @@
+import { Http } from '@angular/http';
+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, Input, AfterViewInit } from '@angular/core';
+import { TdMediaService } from '@covalent/core';
+
+@Component({
+ selector: 'error-checker',
+ template: `
+ <div *ngIf="formField?.touched && formField.invalid" layout="column">
+ <span *ngFor="let err of getFieldErrors()" align="end">{{err}}</span>
+ </div>`
+})
+export class ErrorCheckerComponent {
+
+ @Input() formField: any;
+ @Input() fieldName: string;
+
+ constructor(private $L: LocaleService) {
+ console.log('contructor: ' + this.formField);
+ }
+
+ getFieldErrors() : string[] {
+ if (this.formField.valid) {
+ return []
+ } else {
+ return (<string[]>Object.keys(this.formField.errors)).map((err:string) => this.getErrorMsg(err));
+ }
+ }
+
+ private updateFieldErrors() {
+ }
+
+ private getErrorMsg(err: string) : string{
+ switch(err) {
+ case 'required': {
+ return this.fieldName + ' '+ this.$L.get('is required');
+ }
+ case 'number': {
+ return this.fieldName + ' '+ this.$L.get('should be a number');
+ }
+ default: {
+ return this.fieldName + ' '+ this.$L.get('unknown error') + ' ' + err;
+ }
+ }
+ }
+
+ log(obj: any) {
+ console.log(obj)
+ }
+
+}
+
diff --git a/securis/src/main/webapp/src/app/common/i18n.ts b/securis/src/main/webapp/src/app/common/i18n.ts
index b8132e1..58f1411 100644
--- a/securis/src/main/webapp/src/app/common/i18n.ts
+++ b/securis/src/main/webapp/src/app/common/i18n.ts
@@ -5,13 +5,14 @@
// Use as reference: https://github.com/ngx-translate/core/tree/master/src
@Injectable()
export class LocaleService {
- get URL_TPL() {return 'src/lang/messages-{0}.json'};
+ get URL_TPL() {return 'src/lang/messages_{0}.json'};
+ private _devLang : string = 'en';
private _currentLang : string = null;
private _messages : any = null;
private _elements = new Array<ElementRef>();
private constructor(private http: Http, @Inject('INITIAL_LANG') initLang: string) {
- this._currentLang = initLang || this.getBrowserLang();
+ this.lang = initLang || this.getBrowserLang();
}
get lang() : string {
@@ -21,7 +22,7 @@
set lang(newLang: string) {
this._currentLang = newLang;
this.http.get(this._format(this.URL_TPL, newLang)).subscribe((data) => {
- this._messages = data;
+ this._messages = data.json();
this.reloadTexts();
});
}
@@ -48,7 +49,7 @@
/**
* It works similar to MessageFormat in Java
*/
- _format(str: string, ...params: Array<string>) {
+ _format(str: string, ...params: string[]) {
return str.replace(/\{(\d+)\}/g, function(match, index) {
return params[index];
@@ -78,7 +79,7 @@
* $L.get('hello'); // This returns "hola"
* $L.get('Hello {0}!!', 'John'); // This returns: "Hola John!!" if language is spanish
*/
- get(msg: string) : string {
+ get(msg: string, ...params: string[] ) : string {
if (msg == null) {
return '';
}
@@ -90,16 +91,15 @@
trans_msg = this._messages[msg];
} else if (this._messages[msg.toLowerCase()]) {
trans_msg = this._messages[msg.toLowerCase()];
- } else {
- this._currentLang !== 'es' && console.error("Missing i18 key: " + msg);
+ } else {
+ (this._currentLang !== this._devLang) && console.error("Missing i18 key: " + msg);
trans_msg = msg;
}
}
// Enviar evento cuando el idioma cambia al $rootScope
if (arguments.length === 1) return trans_msg;
- var params = Array.prototype.slice.call(arguments, 1);
- return this._format.apply(trans_msg, params);
+ return this._format(trans_msg, ...params);
}
}
@@ -108,6 +108,7 @@
@Directive({ selector: '[i18n]' })
export class I18nDirective {
constructor(private el: ElementRef, private renderer: Renderer, private $L: LocaleService) {
+ console.log(el);
}
ngAfterViewChecked() {
@@ -124,7 +125,6 @@
})
export class LocaleServiceModule {
static withConfig(initLang?: string): ModuleWithProviders {
- console.log('Init lang with ' + initLang);
return {
ngModule: LocaleServiceModule,
providers: [
diff --git a/securis/src/main/webapp/src/app/common/session.ts b/securis/src/main/webapp/src/app/common/session.ts
new file mode 100644
index 0000000..e6e9402
--- /dev/null
+++ b/securis/src/main/webapp/src/app/common/session.ts
@@ -0,0 +1,30 @@
+import { LocalStorageService } from 'angular-2-local-storage';
+import { Injectable } from '@angular/core';
+
+
+@Injectable()
+export class SeCurisSession {
+
+ sessionData: any = {}
+
+ constructor(private store: LocalStorageService) {
+
+ }
+
+ public get(key: string): any {
+ return this.sessionData[key];
+ }
+
+ public exists(key: string): boolean {
+ return this.sessionData[key] != undefined;
+ }
+
+ public set(key: string, value: any): void {
+ this.sessionData[key] = value;
+ }
+
+ public remove(key: string) : void {
+ delete this.sessionData[key];
+ }
+}
+
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
new file mode 100644
index 0000000..ba627af
--- /dev/null
+++ b/securis/src/main/webapp/src/app/forms/license.form.component.ts
@@ -0,0 +1,53 @@
+import { Http } from '@angular/http';
+import { LicensesService } from '../resources/licenses';
+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';
+
+@Component({
+ selector: 'license-form',
+ templateUrl: 'src/app/forms/license.form.html'
+})
+export class LicenseFormComponent implements AfterViewInit {
+
+ form_title: string = 'Title';
+ form_subtitle: string = '';
+ data: any = {};
+ isNew : boolean = true;
+
+ constructor(private http: Http,
+ private packs: LicensesService,
+ private $L: LocaleService) {
+
+ }
+
+ 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)
+ }
+
+ 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') ;
+ }
+
+
+ ngAfterViewInit(): void {
+ }
+}
+
diff --git a/securis/src/main/webapp/src/app/forms/license.form.html b/securis/src/main/webapp/src/app/forms/license.form.html
new file mode 100644
index 0000000..df65d4d
--- /dev/null
+++ b/securis/src/main/webapp/src/app/forms/license.form.html
@@ -0,0 +1,75 @@
+<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>
+ </div>
+ </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>
+ </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>
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 852dba3..53858be 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
@@ -1,11 +1,16 @@
import { Http } from '@angular/http';
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
+
import { PacksService } from '../resources/packs';
+import { LicenseTypesService } from '../resources/license_types';
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';
+
+
@Component({
selector: 'pack-form',
@@ -19,11 +24,35 @@
licensetypes : IComboOption[];
data: any = {};
isNew : boolean = true;
-
+ fields: any = {
+ 'code': '',
+ 'num_licenses': '',
+ 'init_valid_date': '',
+ 'end_valid_date': '',
+ 'license_preactivation': '',
+ 'license_type_id': '',
+ 'organization_id': '',
+ 'licensetype_code': '',
+ 'organization_name': '',
+ 'preactivation_valid_period': '',
+ 'renew_valid_period': '',
+ 'application_name': '',
+ 'status': '',
+ 'metadata': '',
+ 'comments': '',
+ 'key': '',
+ 'value': '',
+ }
constructor(private http: Http,
+ private toaster: ToastsManager,
+ private licenseTypes: LicenseTypesService,
private packs: PacksService,
private $L: LocaleService) {
-
+ Object.keys(this.fields).forEach(k => this.fields[k] = $L.get(`field.${k}`));
+ }
+
+ public getFieldName(fieldId: string) : string {
+ return this.fields[fieldId];
}
private loadCombos(): void {
@@ -33,23 +62,47 @@
data => this.organizations = (<IComboOption[]>data).sort((e1, e2) => e1.label.localeCompare(e2.label)),
err => console.error('Error loading orgs')
);
- this.http.get('licensetype')
- .map(response => response.json().map((lt : any) => <IComboOption>{id: lt.id, label: `(${lt.code}) ${lt.name}`}))
+ this.licenseTypes.get()
+ .map(list => list.map((lt : any) => <IComboOption>{id: lt.id, label: `(${lt.code}) ${lt.name}`}))
.subscribe(
data => this.licensetypes = (<IComboOption[]>data).sort((e1, e2) => e1.label.localeCompare(e2.label)),
err => console.error('Error loading license types')
);
}
- log(obj: any) {
- console.log(obj)
+ 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'));
+ }
+ );
}
+
+ changeLicType(event) {
+ this.licenseTypes.get(this.data.license_type_id)
+ .map(lt_data => lt_data.metadata)
+ .subscribe(
+ metadata => this.data.metadata = metadata,
+ err => {
+ console.error('Error loading license type metadata');
+ console.error(err);
+ }
+ );
+ }
+
+ changeOrg(event) {
+ console.log(event);
+ console.log(this.data.organization_id);
+ }
ngOnInit(): void {
this.loadCombos();
- this.data = {};
+ // this.data = {};
this.form_title = this.$L.get('Pack data');
- this.form_subtitle = this.$L.get('Create a new licenses pack');
+ this.form_subtitle = this.$L.get(this.isNew ? 'Create a new licenses pack': 'Modify the licenses pack data') ;
}
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 df65d4d..82d8815 100644
--- a/securis/src/main/webapp/src/app/forms/pack.form.html
+++ b/securis/src/main/webapp/src/app/forms/pack.form.html
@@ -1,75 +1,174 @@
-<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-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>
- <md-card-content>
- <div layout="column" layout-align="start center" layout-fill>
+<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="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>
+ <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>
- <!-- 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 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>
- <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 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>
</div>
-</md-card-content>
+</md-dialog-content>
+<div flex></div>
<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>
+<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>
diff --git a/securis/src/main/webapp/src/app/license.list.component.html b/securis/src/main/webapp/src/app/license.list.component.html
new file mode 100644
index 0000000..25969b2
--- /dev/null
+++ b/securis/src/main/webapp/src/app/license.list.component.html
@@ -0,0 +1,51 @@
+<md-toolbar role="toolbar" class="mat-secondary">
+ <span class="push-left-sm">
+ <span class="md-title" i18n>License Packs</span>
+ </span>
+ <span class="push-left-sm" *ngIf="filteredItems < data.length">
+ <span class="md-body-1">{{filteredItems}} of {{data.length}} packs 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)="createPack()">
+ <md-icon>add</md-icon>
+ </button>
+</md-toolbar>
+<md-divider></md-divider>
+<div layout="row" layout-align="center center">
+ <div flex="80" layout="column" layout-align="end center" >
+<td-data-table [data]="filteredData" [columns]="columns" style="width: 100%">
+ <template tdDataTableTemplate="used_licenses" let-row="row">
+ <div layout="row">
+ <td-notification-count color="secondary" [notifications]="row['num_licenses']">
+ </td-notification-count>
+ <td-notification-count color="primary" [notifications]="row['num_available']">
+ </td-notification-count>
+ </div>
+ </template>
+ <template tdDataTableTemplate="code" let-row="row" let-value="value">
+ <div layout="row" layout-align="start center">
+ <span style="white-space: nowrap">{{value}}</span>
+ </div>
+ </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 [mdMenuTriggerFor]="packMenu" aria-label="Pack menu">
+ <md-icon>more_vert</md-icon>
+ </button>
+
+ <md-menu #packMenu="mdMenu">
+ <button md-menu-item *ngFor="let action of pack_menu_options" (click)="packAction(action.command, row)" [disabled]="!isActionAvailable(row)">
+ <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
+ </button>
+ </md-menu>
+ <button md-icon-button (click)="showLicenses(row)" color="accent"><md-icon>arrow_forward</md-icon></button>
+ </div>
+ </template>
+</td-data-table>
+<td-paging-bar #pagingBar [pageSizes]="[10, 20, 40]" [total]="filteredTotal" (change)="page($event)" align="end">
+ <span td-paging-bar-label hide-xs>Rows per page:</span> {{pagingBar.range}} <span hide-xs>of {{pagingBar.total}}</span>
+</td-paging-bar>
+</div>
+</div>
\ 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
new file mode 100644
index 0000000..a14377e
--- /dev/null
+++ b/securis/src/main/webapp/src/app/license.list.component.ts
@@ -0,0 +1,151 @@
+import { Router } from '@angular/router';
+import { MdDialog } from '@angular/material';
+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 { LicensesService } from './resources/licenses';
+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' }
+
+@Component({
+ selector: 'license-list',
+ templateUrl: 'src/app/license.list.component.html'
+})
+export class LicenseListComponent implements AfterViewInit {
+ data: any[] = [];
+ 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: 'Lics', 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 = 'application_name';
+ 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 router: Router,
+ private dialog: MdDialog,
+ private licenseForm: LicenseFormComponent,
+ private licenses: LicensesService) {
+ this.licenses.get().subscribe(
+ list => {
+ this.data = list;
+ this.filter();
+ },
+ err => console.error(err)
+ );
+ }
+
+ ngOnInit(): void {
+ this.filter();
+ }
+
+ createPack() : void {
+ var ref = this.dialog.open(LicenseFormComponent, {
+ height: '50%', // can be px or %
+ width: '40%', // can be px or %
+ });
+ ref.componentInstance.isNew = true;
+ ref.afterClosed().subscribe(result => {
+ console.log(result);
+ this.filter();
+ });
+ }
+
+ editLicense(lic: any) : void {
+ var ref = this.dialog.open(LicenseFormComponent, {
+ height: '50%', // can be px or %
+ width: '40%', // can be px or %
+ });
+ ref.componentInstance.isNew = false;
+ ref.componentInstance.data = lic;
+ ref.afterClosed().subscribe(result => {
+ console.log(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/pack.list.component.html b/securis/src/main/webapp/src/app/pack.list.component.html
index 73a3bfe..25969b2 100644
--- a/securis/src/main/webapp/src/app/pack.list.component.html
+++ b/securis/src/main/webapp/src/app/pack.list.component.html
@@ -12,27 +12,40 @@
</button>
</md-toolbar>
<md-divider></md-divider>
-<td-data-table [data]="filteredData" [columns]="columns">
-
+<div layout="row" layout-align="center center">
+ <div flex="80" layout="column" layout-align="end center" >
+<td-data-table [data]="filteredData" [columns]="columns" style="width: 100%">
<template tdDataTableTemplate="used_licenses" let-row="row">
<div layout="row">
<td-notification-count color="secondary" [notifications]="row['num_licenses']">
</td-notification-count>
- <td-notification-count color="green" [notifications]="row['num_available']">
+ <td-notification-count color="primary" [notifications]="row['num_available']">
</td-notification-count>
</div>
</template>
- <template tdDataTableTemplate="lics" let-row="row">
- <button md-icon-button color="primary"><md-icon>arrow_right</md-icon></button>
+ <template tdDataTableTemplate="code" let-row="row" let-value="value">
+ <div layout="row" layout-align="start center">
+ <span style="white-space: nowrap">{{value}}</span>
+ </div>
</template>
- <template tdDataTableTemplate="menu" let-row="row">
- <div layout="row">
- <button md-icon-button color="primary"><md-icon>arrow_right</md-icon></button>
- <button md-icon-button><md-icon>edit</md-icon></button>
- <button md-icon-button><md-icon>more_vert</md-icon></button>
+ <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 [mdMenuTriggerFor]="packMenu" aria-label="Pack menu">
+ <md-icon>more_vert</md-icon>
+ </button>
+
+ <md-menu #packMenu="mdMenu">
+ <button md-menu-item *ngFor="let action of pack_menu_options" (click)="packAction(action.command, row)" [disabled]="!isActionAvailable(row)">
+ <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
+ </button>
+ </md-menu>
+ <button md-icon-button (click)="showLicenses(row)" color="accent"><md-icon>arrow_forward</md-icon></button>
</div>
</template>
</td-data-table>
-<td-paging-bar #pagingBar [pageSizes]="[10, 20, 40]" [total]="filteredTotal" (change)="page($event)">
+<td-paging-bar #pagingBar [pageSizes]="[10, 20, 40]" [total]="filteredTotal" (change)="page($event)" align="end">
<span td-paging-bar-label hide-xs>Rows per page:</span> {{pagingBar.range}} <span hide-xs>of {{pagingBar.total}}</span>
-</td-paging-bar>
\ No newline at end of file
+</td-paging-bar>
+</div>
+</div>
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/pack.list.component.ts b/securis/src/main/webapp/src/app/pack.list.component.ts
index f931ef8..0af18bb 100644
--- a/securis/src/main/webapp/src/app/pack.list.component.ts
+++ b/securis/src/main/webapp/src/app/pack.list.component.ts
@@ -1,3 +1,4 @@
+import { Router } from '@angular/router';
import { MdDialog } from '@angular/material';
import { TdDataTableService, TdDataTableSortingOrder, ITdDataTableSortChangeEvent, ITdDataTableColumn } from '@covalent/core';
import { IPageChangeEvent } from '@covalent/core';
@@ -42,7 +43,6 @@
export class PackListComponent implements AfterViewInit {
data: any[] = [];
columns: ITdDataTableColumn[] = [
- { name: 'lics', label: '' },
{ name: 'code', label: 'Code', tooltip: 'License pack code' },
{ name: 'application_name', label: 'App name' },
{ name: 'licensetype_code', label: 'License type' },
@@ -61,9 +61,25 @@
sortBy: string = 'application_name';
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 dialog: MdDialog,
private packForm: PackFormComponent,
private packs: PacksService) {
@@ -92,9 +108,13 @@
});
}
+ showLicenses(pack: any) : void {
+ this.router.navigateByUrl('/licenses');
+ }
+
editPack(pack: any) : void {
var ref = this.dialog.open(PackFormComponent, {
- height: '50%', // can be px or %
+ height: '70%', // can be px or %
width: '40%', // can be px or %
});
ref.componentInstance.isNew = false;
diff --git a/securis/src/main/webapp/src/lang/messages_en.json b/securis/src/main/webapp/src/lang/messages_en.json
index 413715e..6b2ae29 100644
--- a/securis/src/main/webapp/src/lang/messages_en.json
+++ b/securis/src/main/webapp/src/lang/messages_en.json
@@ -1,4 +1,22 @@
{
-"": "",
-"": ""
+ "field.code": "Code",
+ "field.num_licenses": "Num. licenses",
+ "field.pack": "Pack",
+ "field.id": "ID",
+ "field.init_valid_date": "Init valid date",
+ "field.end_valid_date": "End valid date",
+ "field.license_preactivation": "License preactivation",
+ "field.license_type_id": "License type",
+ "field.organization_id": "Organization",
+ "field.licensetype_code": "License type",
+ "field.organization_name": "Organization",
+ "field.preactivation_valid_period": "Preactivation valid period",
+ "field.renew_valid_period": "Renew valid period",
+ "field.application_name": "Application name",
+ "field.status": "Status",
+ "field.metadata": "Metadata",
+ "field.key": "Parameter",
+ "field.value": "Value",
+ "field.comments": "Comments",
+ "": ""
}
\ No newline at end of file
--
Gitblit v1.3.2