From 0ec66cd25675f85d21d36d33c9ff4d133e141f87 Mon Sep 17 00:00:00 2001
From: Hamza GRAINI <hamza.graini@xelians.fr>
Date: Thu, 6 Feb 2020 16:46:33 +0100
Subject: [PATCH] New Frontend Input component : Allow only positive numbers &
 upgrade ui-frontend-common to 0.0.14

---
 ui/ui-frontend-common/package-lock.json       |   2 +-
 ui/ui-frontend-common/package.json            |   2 +-
 ui/ui-frontend-common/server.crt              |  18 +++
 ui/ui-frontend-common/server.key              |  27 ++++
 ...tamui-input-positive-number.component.html |  16 +++
 ...tamui-input-positive-number.component.scss |  96 +++++++++++++
 ...ui-input-positive-number.component.spec.ts | 115 +++++++++++++++
 ...vitamui-input-positive-number.component.ts | 133 ++++++++++++++++++
 .../vitamui-input/vitamui-input.component.ts  |   6 +-
 .../vitamui-input/vitamui-input.module.ts     |   5 +-
 .../src/app/modules/helper/injector.module.ts |   1 +
 .../src/app/modules/logger/logger.module.ts   |   9 +-
 .../src/app/modules/vitamui-common.module.ts  |   3 +
 .../testing/src/vitamui-common-test.module.ts |  19 +++
 ui/ui-frontend/package.json                   |   2 +-
 .../projects/demo/src/app/app.module.ts       |   1 +
 .../components/components.component.html      |   7 +
 .../components/components.component.ts        |   9 ++
 18 files changed, 458 insertions(+), 13 deletions(-)
 create mode 100644 ui/ui-frontend-common/server.crt
 create mode 100644 ui/ui-frontend-common/server.key
 create mode 100644 ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.html
 create mode 100644 ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.scss
 create mode 100644 ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.spec.ts
 create mode 100644 ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.ts

diff --git a/ui/ui-frontend-common/package-lock.json b/ui/ui-frontend-common/package-lock.json
index 8982704c..2b461c20 100644
--- a/ui/ui-frontend-common/package-lock.json
+++ b/ui/ui-frontend-common/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "ui-frontend-common",
-  "version": "0.0.13",
+  "version": "0.0.14",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/ui/ui-frontend-common/package.json b/ui/ui-frontend-common/package.json
index f3a98a6a..893df331 100644
--- a/ui/ui-frontend-common/package.json
+++ b/ui/ui-frontend-common/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ui-frontend-common",
-  "version": "0.0.13",
+  "version": "0.0.14",
   "main": "src/index.ts",
   "scripts": {
     "ng": "ng",
diff --git a/ui/ui-frontend-common/server.crt b/ui/ui-frontend-common/server.crt
new file mode 100644
index 00000000..0e69ae52
--- /dev/null
+++ b/ui/ui-frontend-common/server.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1zCCAb+gAwIBAgIJZQPZzFAai/+/MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
+BAMTCWxvY2FsaG9zdDAeFw0xODA3MTIwODEyNDBaFw0xOTA3MTIwODEyNDBaMBQx
+EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJKigWDcOUD3md5DgbINHi/uhInG5QoT/4B+DjEtSGLuHo3qqpnanTDTGxGZ
+N5Tro1cRrv7L9vuXduPBUgDKdOjORE/wq7O/4k4wxaIaH+AZS/5iA/Ypjv4/qwLf
+o4WNTRZrPMqLTJ4cL+mzhfhbo5bZxJxIrI/9WRbgB20i1g8VWSVDaL4p0NhhtJGZ
+mBSVfbZ8DUz7TNGJE77sv77RKXH520kpJ5/v6t0hbWzKIKPDbl5gwXJMu6RxAUQO
+HZ7s96x32prwREiNFwtAIWotcOrMuTNb3hHKn9/V4rWVc+5cPP00ywvVt79AWX2Q
++7JYOxHWYrubn83/XKw2jVsTva8CAwEAAaMsMCowKAYDVR0RBCEwH4IdaHR0cHM6
+Ly9kZXYtZmxvdy50ZWFtZGxhYi5jb20wDQYJKoZIhvcNAQELBQADggEBAAa/WjtA
+wHlcsG43pAQYCsLg3IbiVTJeYqvXTHj8jdydj0pUVX97RMJfNE6pIMzQQE57u8US
+DrQB0PqEzEFC8iRQeNqxB6gYuLwaGlDO1SR1ITf5wJcneXnvGmy+OVJRvQbgwE9N
+iptZip+juuVpplNOKtfpGMD83p98FRuT33VsNCS4OEIATFtlm3jeVC4T1yWqebTI
+BmNujsRu90Tt7iKW3C3qh4Ja4Wxp5Cj7QJRgfoB0sCDajSzU5B1C9VJy3k/jdWWV
+f7oXTGI+qmvRllz0GJm1iRuG7wbN8oeMzi9lzonyZstggzdG7C+uGjjsbdfGX1qL
+++nXSPEFocrcdRE=
+-----END CERTIFICATE-----
diff --git a/ui/ui-frontend-common/server.key b/ui/ui-frontend-common/server.key
new file mode 100644
index 00000000..60ef72ea
--- /dev/null
+++ b/ui/ui-frontend-common/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAkqKBYNw5QPeZ3kOBsg0eL+6EicblChP/gH4OMS1IYu4ejeqq
+mdqdMNMbEZk3lOujVxGu/sv2+5d248FSAMp06M5ET/Crs7/iTjDFohof4BlL/mID
+9imO/j+rAt+jhY1NFms8yotMnhwv6bOF+FujltnEnEisj/1ZFuAHbSLWDxVZJUNo
+vinQ2GG0kZmYFJV9tnwNTPtM0YkTvuy/vtEpcfnbSSknn+/q3SFtbMogo8NuXmDB
+cky7pHEBRA4dnuz3rHfamvBESI0XC0Ahai1w6sy5M1veEcqf39XitZVz7lw8/TTL
+C9W3v0BZfZD7slg7EdZiu5ufzf9crDaNWxO9rwIDAQABAoIBAE+/JVHCMzkL75ib
+ahulWreCpn4vtzyl55y/8YP5NpbnHaLc7u9Bn5+AEAagJ0RMasbdjShxUN8/Xp86
+8hgQA0jhdPFs2FSnlLIlgDZKsu8zksrED5d+vo+znJOxgMMPN89rfuJAo+iRN9WH
+luKdI/jUckL0mzSr+hmguSk3euc0RwwTmOWP/SghOvVbPkMbO1tUjAc2uD3hf+rS
+jj6bMeOakT8+Y8WvANTSo5skMOX5GB9w3J95rDrO2lCqso+Bgdy2ibU0fYrdIE0X
+yc9Ypegl5Z0TcyqEPS4BsMhZaneaZj7XQFrD2dj5x4c/i6MQGXXiacPSP+iAgrAe
+Y94CC8ECgYEA2ABiJyWcn+64QFdBUMKEzMWL5jGmvAiiVQEX1/bhV8pUhBCobzth
+a1thE1I3zyLosfyAY1ojj9kmXwmeqHhKZZai+U8wkdDwNppB/4CMMnx9FO5kM4kd
+OIGOvuiJZvOk8kIIySqMLGY3J44T6UQeEXpGyICiKXTlr/RhopMOWf8CgYEArcnF
+oA1kA/4HYSHsOiyMGSQxgQxXmbraql6aKLA9CsPBSf3pCDu9aSREa9/+A1d/WDX4
+PeoITk9XhoV//1O9qu9uS8k58EU6zEkdV18L8/iTjA6o6kHysE/2ylIUoplB0L+V
+6ZascYcfK4VzxXyjI4BZD5AHq9pA8LQWy6KOvFECgYEApIbOPKFChvOvdpq/zoML
+4mnKYQGKzgkJlRPrFH4hMNyVua5yjZ8+WibVb4Edr3IYqpH5PTQIiGZP+u354rsV
+eAHgi2PNTBRJFF41TSeeIkp+f/YBbtvO3R6aG0JGfpuxFTJFPO1ireMBuehXtENF
+X+yyg8CvREKdPYQ45jt7IAMCgYEAkPlkKithhs8QOuBAnxrwWDzQKzYvkafFqCA4
++75hfaxlfyMYley4CpDdnxwBW6pPKjgDeSrVePZJLogJiebCr2kDGqen9J7b+PT5
+TByW7RQticXk9V7EZH6ggpDMdAPjWo+oMG+oNSCiSP0P4ewib4gvQ4NEUwFD8Uha
+R8+4wLECgYBUbSJFJXLbWMbb8Ow6OK2tzup8sPZi+JUtEQYOjQ1u1l3UhP7mrHXX
+IaTyrwFgo0mUcbuVfG3bGFBZJPHvRyx2h6HPFt+7zEdOEsYegzy+YbPM9yhafoVS
+nK2tDTCVLITd47jUpr9nM/N7oJ2EADMkfZfAudQbrqmflOoHZd8IJQ==
+-----END RSA PRIVATE KEY-----
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.html b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.html
new file mode 100644
index 00000000..b41a9337
--- /dev/null
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.html
@@ -0,0 +1,16 @@
+<div class="vitamui-input" [class.disabled]="disabled">
+  <label>
+    {{placeholder}}
+    <span *ngIf="required" class="required-marker">*</span>
+  </label>
+
+  <input #vitamUIInputPositiveNumber [type]="type" [required]="required" [disabled]="disabled" [autofocus]="autofocus"
+    [attr.maxlength]="maxlength" [attr.min]="min" (blur)="onBlur()" (focus)="onFocus()" [(ngModel)]="value"
+    (ngModelChange)="onValueChange($event)" (keypress)="onKeyPress($event)">
+
+
+  <mat-spinner diameter="25" color="accent"></mat-spinner>
+</div>
+<div class="vitamui-input-errors">
+  <ng-content></ng-content>
+</div>
\ No newline at end of file
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.scss b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.scss
new file mode 100644
index 00000000..8a8fdc5a
--- /dev/null
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.scss
@@ -0,0 +1,96 @@
+@import '../../../../sass/variables/colors';
+@import '../../../../sass/mixins/elevation';
+
+$input-height: 50px;
+$input-small-height: 34px;
+$anim-timing: 150ms ease-out;
+
+:host {
+    display: inline-block;
+
+    &.vitamui-focused .vitamui-input {
+        border-color: #a6a6a6;
+    }
+
+    &.vitamui-focused .vitamui-input,
+    &.vitamui-float .vitamui-input {
+        label {
+            transform: scale(0.7) translateY(-15px);
+        }
+
+        input {
+            margin-top: 15px;
+        }
+    }
+
+    &.ng-valid.ng-touched .vitamui-input {
+        border-color: #43ea2a;
+    }
+
+    &.ng-invalid.ng-touched .vitamui-input {
+        border-color: #ff0000;
+    }
+}
+
+.vitamui-input {
+    display: inline-flex;
+    align-items: center;
+    position: relative;
+    height: $input-height;
+    width: 100%;
+    border-radius: $input-height / 2;
+    border: solid 1px #f0f0f0;
+    background-color: #ffffff;
+    padding: 8px 30px;
+    transition: border-color $anim-timing;
+    vertical-align: top;
+    @include elevation-1;
+
+    mat-spinner {
+        position: absolute;
+        top: 12px;
+        right: 12px;
+        display: none;
+    }
+}
+
+.vitamui-input.disabled {
+    opacity: 0.4;
+}
+
+:host.ng-pending {
+    .vitamui-input mat-spinner {
+        display: block;
+    }
+}
+
+.vitamui-input-errors {
+    min-height: 30px;
+}
+
+input {
+    color: $charcoal-grey;
+    font-size: 15px;
+    font-weight: 500;
+    font-family: 'Roboto';
+    background: none;
+    border: none;
+    transition: margin $anim-timing;
+    outline: none;
+    width: 100%;
+}
+
+label {
+    color: $greyish-two;
+    font-size: 15px;
+    position: absolute;
+    left: 30px;
+    transform-origin: left;
+    transition: transform $anim-timing;
+    pointer-events: none;
+    white-space: nowrap;
+
+    .required-marker {
+        color: $blood-orange;
+    }
+}
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.spec.ts b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.spec.ts
new file mode 100644
index 00000000..a1b554f2
--- /dev/null
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.spec.ts
@@ -0,0 +1,115 @@
+/*
+ * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
+ * and the signatories of the "VITAM - Accord du Contributeur" agreement.
+ *
+ * contact@programmevitam.fr
+ *
+ * This software is a computer program whose purpose is to implement
+ * implement a digital archiving front-office system for the secure and
+ * efficient high volumetry VITAM solution.
+ *
+ * This software is governed by the CeCILL-C license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-C
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+import { Component, ViewChild } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, NgModel } from '@angular/forms';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+
+import { input } from '../../../../../testing/src/helpers';
+import { VitamUIInputPositiveNumberComponent } from './vitamui-input-positive-number.component';
+
+@Component({
+  template: `
+    <vitamui-common-input-positive-number [(ngModel)]="value" #input="ngModel"></vitamui-common-input-positive-number>
+  `
+})
+class TesthostComponent {
+  @ViewChild(VitamUIInputPositiveNumberComponent, {static: false}) VitamUIInputPositiveNumberComponent: VitamUIInputPositiveNumberComponent;
+  @ViewChild('input', {static: false}) ngModel: NgModel;
+
+  value = 'initial value';
+}
+
+let testhost: TesthostComponent;
+let fixture: ComponentFixture<TesthostComponent>;
+
+describe('VitamUIInputPositiveNumberComponent', () => {
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [FormsModule, NoopAnimationsModule, MatProgressSpinnerModule],
+      declarations: [VitamUIInputPositiveNumberComponent, TesthostComponent]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TesthostComponent);
+    testhost = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(testhost).toBeTruthy();
+  });
+
+  it('should display the value', async(() => {
+    testhost.value = 'value to display';
+    fixture.detectChanges();
+    fixture.whenStable().then(() => {
+      fixture.detectChanges();
+      expect(testhost.VitamUIInputPositiveNumberComponent.value).toBe('value to display');
+    });
+  }));
+
+  it('should emit the typed in value', () => {
+    const elInput = fixture.nativeElement.querySelector('input');
+    input(elInput, 'typed in value');
+    fixture.detectChanges();
+    expect(testhost.value).toBe('typed in value');
+  });
+
+  it('should focus the input on click', () => {
+    const elVitamUIInput = fixture.nativeElement.querySelector('vitamui-common-input-positive-number');
+    const elInput = fixture.nativeElement.querySelector('input');
+    elVitamUIInput.click();
+    expect(document.activeElement).toBe(elInput);
+  });
+
+  it('should set focus to true', () => {
+    testhost.VitamUIInputPositiveNumberComponent.onFocus();
+    expect(testhost.VitamUIInputPositiveNumberComponent.focused).toBe(true);
+  });
+
+  it('should set focus to false', () => {
+    testhost.VitamUIInputPositiveNumberComponent.onFocus();
+    testhost.VitamUIInputPositiveNumberComponent.onBlur();
+    expect(testhost.VitamUIInputPositiveNumberComponent.focused).toBe(false);
+  });
+
+});
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.ts b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.ts
new file mode 100644
index 00000000..41b961ac
--- /dev/null
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input-positive-number.component.ts
@@ -0,0 +1,133 @@
+/*
+ * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2020)
+ * and the signatories of the "VITAM - Accord du Contributeur" agreement.
+ *
+ * contact@programmevitam.fr
+ *
+ * This software is a computer program whose purpose is to implement
+ * implement a digital archiving front-office system for the secure and
+ * efficient high volumetry VITAM solution.
+ *
+ * This software is governed by the CeCILL-C license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL-C
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+/* tslint:disable: no-use-before-declare */
+import { coerceBooleanProperty } from '@angular/cdk/coercion';
+import { Component, ElementRef, forwardRef, HostBinding, HostListener, Input, ViewChild } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+
+export const VITAMUI_INPUT_VALUE_ACCESSOR: any = {
+  provide: NG_VALUE_ACCESSOR,
+  useExisting: forwardRef(() => VitamUIInputPositiveNumberComponent),
+  multi: true
+};
+
+@Component({
+  selector: 'vitamui-common-input-positive-number',
+  templateUrl: './vitamui-input-positive-number.component.html',
+  styleUrls: ['./vitamui-input-positive-number.component.scss'],
+  providers: [VITAMUI_INPUT_VALUE_ACCESSOR]
+})
+export class VitamUIInputPositiveNumberComponent implements ControlValueAccessor {
+
+  @Input() type = 'text';
+  @Input() maxlength: number;
+  @Input() min: number;
+  @Input() placeholder: string;
+  @Input() autofocus: boolean;
+  @Input()
+  get required(): boolean { return this._required; }
+  set required(value: boolean) { this._required = coerceBooleanProperty(value); }
+  // tslint:disable-next-line:variable-name
+  private _required = false;
+
+  @Input()
+  get disabled(): boolean { return this._disabled; }
+  set disabled(value: boolean) { this._disabled = coerceBooleanProperty(value); }
+  // tslint:disable-next-line:variable-name
+  private _disabled = false;
+  @ViewChild('vitamUIInputPositiveNumber', { static: false }) private input: ElementRef;
+
+  @HostBinding('class.vitamui-focused') focused = false;
+  @HostBinding('class.vitamui-float') labelFloat = false;
+
+  value: string | number;
+
+  onChange = (_: any) => { };
+  onTouched = () => { };
+  onKeyPress = (_: any) => {};
+
+  @HostListener('click')
+  onClick() {
+    this.input.nativeElement.focus();
+  }
+
+  writeValue(value: string | number) {
+    this.value = value;
+    this.labelFloat = !!this.value;
+  }
+
+  registerOnChange(fn: any): void {
+    this.onChange = fn;
+  }
+
+  registerOnTouched(fn: any): void {
+    this.onTouched = fn;
+  }
+
+  onTextChange(value: string) {
+    this.labelFloat = !!this.value;
+    this.onChange(value);
+  }
+
+  onNumberChange(value: number) {
+    const badInput = this.input.nativeElement.validity.badInput;
+    this.labelFloat = badInput || this.value !== null;
+    this.onChange(value);
+  }
+
+  onValueChange(value: string) {
+    if (this.type !== 'number' || value === '') {
+      this.onTextChange(value);
+    } else {
+      this.onNumberChange(Number(value));
+    }
+  }
+
+  onFocus() {
+    this.focused = true;
+  }
+
+  onBlur() {
+    this.focused = false;
+    this.onTouched();
+  }
+
+  setDisabledState(isDisabled: boolean) {
+    this.disabled = isDisabled;
+  }
+
+}
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts
index 90dedd55..6cdfcf5f 100644
--- a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.component.ts
@@ -112,10 +112,10 @@ export class VitamUIInputComponent implements ControlValueAccessor, OnInit {
   }
 
   onValueChange(value: string) {
-    if(this.type === 'number') {
-      this.onNumberChange(Number(value));
-    }else {
+    if (this.type !== 'number' || value === '') {
       this.onTextChange(value);
+    } else {
+      this.onNumberChange(Number(value));
     }
   }
 
diff --git a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.module.ts b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.module.ts
index 12bf1999..b3c65bcc 100644
--- a/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.module.ts
+++ b/ui/ui-frontend-common/src/app/modules/components/vitamui-input/vitamui-input.module.ts
@@ -40,6 +40,7 @@ import { FormsModule } from '@angular/forms';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 
 import { VitamUIInputErrorComponent } from './vitamui-input-error.component';
+import { VitamUIInputPositiveNumberComponent } from './vitamui-input-positive-number.component';
 import { VitamUIInputComponent } from './vitamui-input.component';
 import { VitamUITextareaComponent } from './vitamui-textarea.component';
 
@@ -49,7 +50,7 @@ import { VitamUITextareaComponent } from './vitamui-textarea.component';
     FormsModule,
     MatProgressSpinnerModule,
   ],
-  declarations: [VitamUIInputComponent, VitamUIInputErrorComponent, VitamUITextareaComponent],
-  exports: [VitamUIInputComponent, VitamUIInputErrorComponent, VitamUITextareaComponent]
+  declarations: [VitamUIInputComponent, VitamUIInputErrorComponent, VitamUITextareaComponent, VitamUIInputPositiveNumberComponent],
+  exports: [VitamUIInputComponent, VitamUIInputErrorComponent, VitamUITextareaComponent, VitamUIInputPositiveNumberComponent]
 })
 export class VitamUIInputModule { }
diff --git a/ui/ui-frontend-common/src/app/modules/helper/injector.module.ts b/ui/ui-frontend-common/src/app/modules/helper/injector.module.ts
index f58c8ec2..524479a4 100644
--- a/ui/ui-frontend-common/src/app/modules/helper/injector.module.ts
+++ b/ui/ui-frontend-common/src/app/modules/helper/injector.module.ts
@@ -45,6 +45,7 @@ This module must be loaded in AppModule only
   declarations: []
 })
 export class InjectorModule {
+  // tslint:disable-next-line:no-shadowed-variable
   constructor(injector: Injector, @Optional() @SkipSelf() injectorModule: InjectorModule) {
     throwIfAlreadyLoaded(injectorModule, this.constructor.name);
     InjectorHelper.injector = injector;
diff --git a/ui/ui-frontend-common/src/app/modules/logger/logger.module.ts b/ui/ui-frontend-common/src/app/modules/logger/logger.module.ts
index 1656814f..436a3b4b 100644
--- a/ui/ui-frontend-common/src/app/modules/logger/logger.module.ts
+++ b/ui/ui-frontend-common/src/app/modules/logger/logger.module.ts
@@ -41,12 +41,11 @@ import { LoggerService } from './logger.service';
 import { NoLogService } from './no-log.service';
 
 export function loggerFactory(environment) {
-  // Temporary removal for debug purposes
-  // if (environment !== undefined && environment.production) {
-  //   return new NoLogService();
-  // } else {
+  if (environment && environment.production) {
+    return new NoLogService();
+  } else {
     return new LoggerService();
-  // }
+  }
 }
 
 // @dynamic
diff --git a/ui/ui-frontend-common/src/app/modules/vitamui-common.module.ts b/ui/ui-frontend-common/src/app/modules/vitamui-common.module.ts
index e0827258..aefaade9 100644
--- a/ui/ui-frontend-common/src/app/modules/vitamui-common.module.ts
+++ b/ui/ui-frontend-common/src/app/modules/vitamui-common.module.ts
@@ -40,6 +40,7 @@ import { APP_INITIALIZER, NgModule } from '@angular/core';
 import { MatDialogModule } from '@angular/material/dialog';
 import { MatSnackBarModule } from '@angular/material/snack-bar';
 import { VitamUIDisplayNodeModule } from './components/vitamui-display-node/vitamui-display-node.module';
+import { LoggerModule } from './logger/logger.module';
 
 import { AccountModule } from './account/account.module';
 import { ApplicationSelectContentModule } from './components/application-select-content/application-select-content.module';
@@ -118,6 +119,7 @@ export function startupServiceFactory(startupService: StartupService) {
     InfiniteScrollModule,
     LevelInputModule,
     LogbookModule,
+    LoggerModule,
     NavbarModule,
     OrderByButtonModule,
     OrderDropdownModule,
@@ -162,6 +164,7 @@ export function startupServiceFactory(startupService: StartupService) {
     InfiniteScrollModule,
     LevelInputModule,
     LogbookModule,
+    LoggerModule,
     NavbarModule,
     OrderByButtonModule,
     OrderDropdownModule,
diff --git a/ui/ui-frontend-common/testing/src/vitamui-common-test.module.ts b/ui/ui-frontend-common/testing/src/vitamui-common-test.module.ts
index 08496c35..6de862c4 100644
--- a/ui/ui-frontend-common/testing/src/vitamui-common-test.module.ts
+++ b/ui/ui-frontend-common/testing/src/vitamui-common-test.module.ts
@@ -106,6 +106,23 @@ export class VitamUIInputStubComponent implements ControlValueAccessor {
   registerOnTouched() {}
 }
 
+@Component({
+  selector: 'vitamui-common-input-positive-number',
+  template: '',
+  providers: [{
+    provide: NG_VALUE_ACCESSOR,
+    useExisting: forwardRef(() => VitamUIInputPositiveNumberStubComponent),
+    multi: true,
+  }]
+})
+export class VitamUIInputPositiveNumberStubComponent implements ControlValueAccessor {
+  @Input() placeholder: any;
+
+  writeValue() {}
+  registerOnChange() {}
+  registerOnTouched() {}
+}
+
 @Component({
   selector: 'vitamui-common-list-input',
   template: '',
@@ -319,6 +336,7 @@ export class RowCollapseTriggerForStubDirective {
     VitamUIEditableToggleGroupStubComponent,
     VitamUIFieldErrorStubComponent,
     VitamUIInputErrorStubComponent,
+    VitamUIInputPositiveNumberStubComponent,
     VitamUIInputStubComponent,
     VitamUIListInputStubComponent,
     VitamUISlideToggleStubComponent,
@@ -347,6 +365,7 @@ export class RowCollapseTriggerForStubDirective {
     VitamUIEditableToggleGroupStubComponent,
     VitamUIFieldErrorStubComponent,
     VitamUIInputErrorStubComponent,
+    VitamUIInputPositiveNumberStubComponent,
     VitamUIInputStubComponent,
     VitamUIListInputStubComponent,
     VitamUISlideToggleStubComponent,
diff --git a/ui/ui-frontend/package.json b/ui/ui-frontend/package.json
index f43cac0e..2d9a17a3 100644
--- a/ui/ui-frontend/package.json
+++ b/ui/ui-frontend/package.json
@@ -60,7 +60,7 @@
     "ngx-color-picker": "^9.0.0",
     "rxjs": "^6.5.2",
     "tslib": "^1.9.0",
-    "ui-frontend-common": "file:../ui-frontend-common/ui-frontend-common-0.0.13.tgz",
+    "ui-frontend-common": "file:../ui-frontend-common/ui-frontend-common-0.0.14.tgz",
     "underscore": "^1.9.1",
     "web-animations-js": "^2.3.2",
     "zone.js": "~0.9.1"
diff --git a/ui/ui-frontend/projects/demo/src/app/app.module.ts b/ui/ui-frontend/projects/demo/src/app/app.module.ts
index 47f60bf8..5c65125f 100644
--- a/ui/ui-frontend/projects/demo/src/app/app.module.ts
+++ b/ui/ui-frontend/projects/demo/src/app/app.module.ts
@@ -73,6 +73,7 @@ import { SubrogationDemoModule } from './demo/subrogation-demo/subrogation-demo.
     ComponentDemoModule,
     IconDemoModule,
     AppGuardDemoModule,
+    LoggerModule.forRoot(),
     RouterModule.forRoot([
       { path: 'subrogation-demo', component: SubrogationDemoComponent },
       {
diff --git a/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.html b/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.html
index 575176f7..6fe43c24 100644
--- a/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.html
+++ b/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.html
@@ -17,6 +17,13 @@
     </vitamui-common-input>
   </div>
 
+  <h3>Input Positive Number</h3>
+  <div class="demo-block">
+    <vitamui-common-input-positive-number placeholder="Number Input" [(ngModel)]="VitamUIInputPositiveNumberValue"
+       required (keypress)="onKeyPress($event)" #VitamUIInputPositiveNumber="ngModel" type="number" min="0">
+    </vitamui-common-input-positive-number>
+  </div>
+
   <div class="demo-block">
     <vitamui-common-slide-toggle>Slide Toggle</vitamui-common-slide-toggle>
   </div>
diff --git a/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.ts b/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.ts
index a7e38c22..c340ba4b 100644
--- a/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.ts
+++ b/ui/ui-frontend/projects/demo/src/app/demo/component-demo/components/components.component.ts
@@ -55,6 +55,7 @@ export class ComponentsComponent implements OnInit {
   applications: Application[];
 
   vitamuiInputValue: string;
+  vitamUIInputPositiveNumberValue: number;
   vitamuiEmailValue = 'toto@vitamui.com';
   vitamuiTextValue = 'Some text value';
   vitamuiTextareaValue = 'Some text value';
@@ -114,4 +115,12 @@ export class ComponentsComponent implements OnInit {
     this.confirmDialogService.confirm(this.confirmDialogTemplate).subscribe(() => this.confirmResult = true);
   }
 
+  onKeyPress(event: KeyboardEvent): boolean {
+    // tslint:disable-next-line: deprecation
+    const charCode = (event.which) ? event.which : event.keyCode;
+    if (charCode > 31 && (charCode < 48 || charCode > 57)) {
+      return false;
+    }
+    return true;
+  }
 }
-- 
GitLab