merge from ecomp a88f0072 - Modern UI

Issue-ID: VID-378
Change-Id: Ibcb23dd27f550cf32ce2fe0239f0f496ae014ff6
Signed-off-by: Ittay Stern <ittay.stern@att.com>
diff --git a/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.spec.ts b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.spec.ts
new file mode 100644
index 0000000..6194aad
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.spec.ts
@@ -0,0 +1,157 @@
+import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
+import {DynamicInputsComponent} from "./dynamic-inputs.component";
+import {async, ComponentFixture, getTestBed, TestBed} from "@angular/core/testing";
+import {CUSTOM_ELEMENTS_SCHEMA} from "@angular/core";
+import {FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, ValidatorFn} from "@angular/forms";
+import {BrowserModule} from "@angular/platform-browser";
+import {CommonModule} from "@angular/common";
+import {RouterTestingModule} from "@angular/router/testing";
+import {DynamicInputLabelPipe} from "../../pipes/dynamicInputLabel/dynamic-input-label.pipe";
+import {DynamicNumber} from "../../models/dynamicInput";
+
+
+describe('DynamicInputs Component', () => {
+  let component: DynamicInputsComponent;
+  let fixture: ComponentFixture<DynamicInputsComponent>;
+
+  beforeAll(done => (async () => {
+    TestBed.configureTestingModule({
+      imports: [BrowserModule, CommonModule, FormsModule, HttpClientTestingModule, RouterTestingModule, ReactiveFormsModule],
+      declarations: [DynamicInputsComponent, DynamicInputLabelPipe],
+      providers : [FormBuilder],
+      schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+    });
+    await TestBed.compileComponents();
+
+    fixture = TestBed.createComponent(DynamicInputsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  })().then(done).catch(done.fail));
+
+  test('should be defined', () => {
+    expect(component).toBeDefined();
+  });
+
+  test('isDynamicNumber should return item', () => {
+    let options = {
+      minLength : 10,
+      maxLength : 10
+    };
+
+    let dynamicNumber : DynamicNumber = new DynamicNumber(<any>options);
+    expect(component.isDynamicNumber(dynamicNumber)).toBeDefined();
+  });
+
+  test('buildValidators should return validator', () => {
+    let options = {
+      minLength : 10,
+      maxLength : 10,
+      max : 10,
+      min : 1
+    };
+
+    let dynamicNumber : DynamicNumber = new DynamicNumber(<any>options);
+    let validator : ValidatorFn = component.buildValidators(dynamicNumber);
+    expect(validator).toBeDefined();
+  });
+
+
+  test('ngOnInit', ()=>{
+    component.group = new FormGroup({
+
+    });
+      component.list = [
+        {
+          type : 'select',
+          value : 'optionName',
+          name : 'multiSelectControl',
+          optionList : [{
+            isDataLoading : true,
+            name : 'optionName',
+            id : 'id'
+          }]
+        },
+        {
+          type : 'select',
+          value : 'optionName',
+          name : 'multiSelectControl',
+          optionList : [{
+            isDataLoading : true,
+            name : 'optionName',
+            id : 'id'
+          }]
+        },
+        {
+          type : 'multi_select',
+          value : 'optionName',
+          name : 'selectControl',
+          optionList : [{
+            isDataLoading : true,
+            name : 'optionName',
+            id : 'id'
+          }]
+        },
+        {
+          type : 'multi_select',
+          value : 'optionName',
+          name : 'selectControl',
+          optionList : [{
+            isDataLoading : true,
+            name : 'optionName'
+          }]
+        },
+        {
+          type : 'boolean',
+          value : true,
+          name : 'booleanControl'
+        },
+        {
+          type : 'boolean',
+          name : 'booleanControl2'
+        },
+        {
+          type : 'number',
+          value : 100,
+          name : 'numberControl'
+        },
+        {
+          type : 'file',
+          value : 'someValue',
+          name : 'fileControl'
+        },
+        {
+          type : 'checkbox',
+          value : true,
+          name : 'checkboxControl'
+        },
+        {
+          type : 'map',
+          value : true,
+          name : 'mapControl'
+        },
+        {
+          type : 'list',
+          value : true,
+          name : 'listControl'
+        },
+        {
+          type : 'default',
+          value : true,
+          name : 'defaultControl'
+        }
+      ];
+
+      component.ngOnInit();
+      expect(component.group.controls['multiSelectControl'].value).toEqual('id');
+      expect(component.group.controls['selectControl'].value).toEqual('optionName');
+      expect(component.group.controls['booleanControl'].value).toEqual(true);
+      expect(component.group.controls['booleanControl2'].value).toEqual(false);
+      expect(component.group.controls['numberControl'].value).toEqual(100);
+      expect(component.group.controls['fileControl'].value).toEqual('someValue');
+      expect(component.group.controls['checkboxControl'].value).toEqual(true);
+      expect(component.group.controls['mapControl'].value).toEqual(true);
+      expect(component.group.controls['listControl'].value).toEqual(true);
+      expect(component.group.controls['defaultControl'].value).toEqual(true);
+  })
+
+});
diff --git a/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.ts b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.ts
new file mode 100644
index 0000000..096a51e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {DynamicInput, DynamicMultiSelect, DynamicNumber, DynamicSelect} from "../../models/dynamicInput";
+
+@Component({
+  selector: 'dynamic-inputs',
+  templateUrl: './dynamic-inputs.html',
+  styleUrls: ['./dynamic-inputs.scss']
+})
+
+export class DynamicInputsComponent implements OnInit{
+  @Input() public list:any[] = [];
+  @Input() public group: FormGroup;
+
+  private dynamicList:DynamicInput<any>[] = [];
+
+  isDynamicNumber(item: any): item is DynamicNumber {
+    return item;
+  }
+
+  buildValidators(item: DynamicInput<any>) {
+    let validatorArr = [];
+    item.maxLength && validatorArr.push(Validators.maxLength(item.maxLength));
+    item.minLength && validatorArr.push(Validators.minLength(item.minLength));
+    if(this.isDynamicNumber(item)) {
+      item.max && validatorArr.push(Validators.max(item.max));
+      item.min && validatorArr.push(Validators.min(item.min));
+    }
+    return Validators.compose(validatorArr);
+  }
+
+  ngOnInit(): void {
+    this.list.forEach((item)=> {
+      let dynamicItem: DynamicInput<any>;
+      switch (item.type) {
+        case 'multi_select':
+          item.optionList.forEach(function(option) { option.id = option.id||option.name;
+          option.itemName = option.name;});
+          item.settings = {
+            disabled: !item.isEnabled,
+            text: item.prompt,
+          };
+          dynamicItem = new DynamicMultiSelect(item);
+          break;
+        case 'select':
+          let defaultValue:any = item.optionList.find((option) => option.isDataLoading && option.name);
+          item.value = defaultValue && defaultValue.id;
+          dynamicItem = new DynamicSelect(item);
+          break;
+        case 'boolean':
+          item.value = item.value || false;
+          item.optionList = [{name: true, isPermitted: true, isDataLoading: item.value}, {name: false, isPermitted: true, isDataLoading: !item.value}];
+
+          dynamicItem = new DynamicSelect(item);
+          break;
+        case 'number':
+          dynamicItem = new DynamicNumber(item);
+          break;
+        case 'file':
+          dynamicItem = new DynamicInput<any>(item);
+          break;
+        case 'checkbox':
+          dynamicItem = new DynamicInput<boolean>(item);
+          break;
+        case 'map':
+          item.prompt = "{<key1>: <value1>,\.\.\.,<keyN>: <valueN>}";
+          dynamicItem = new DynamicInput<string>(item);
+          break;
+        case 'list':
+          item.prompt = "[<value1>,...,<valueN>]";
+          dynamicItem = new DynamicInput<string>(item);
+          break;
+        default: dynamicItem = new DynamicInput<string>(item);
+      }
+      this.dynamicList.push(dynamicItem);
+      this.group.addControl(dynamicItem.name, new FormControl({value: dynamicItem.value, disabled: !dynamicItem.isEnabled}, this.buildValidators(dynamicItem)));
+    })
+  }
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.html b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.html
new file mode 100644
index 0000000..740b798
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.html
@@ -0,0 +1,22 @@
+<div *ngFor="let item of dynamicList">
+  <div id="{{item.id}}" class="details-item" [ngSwitch]="item.type" [formGroup]="group" [hidden]="!item.isVisible">
+    <label  [ngClass]="{'required' : item.isRequired && item.isVisible}">{{item.name | dynamicInputLabel }}</label>
+    <select *ngSwitchCase="item.type === 'select'|| item.type === 'boolean'? item.type: ''" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" title="{{item.description}}" [required]="item.isRequired && item.isVisible"  maxlength="{{item.maxLength}}" minlength="{{item.minLength}}">
+      <option value="null" [selected]="item.value == null || item.value == undefined" hidden disabled>{{item.prompt}}</option>
+      <option *ngFor="let option of item.optionList" [ngValue]="option.id || option.name" [disabled]="!option.isPermitted" [selected]="option.isDataLoading">{{option.name}}</option>
+    </select>
+    <angular2-multiselect *ngSwitchCase="'multi_select'" [formControlName]="item.name" [(ngModel)]="item.selectedItems" [data]="item.optionList" [settings]="item.settings" title="{{item.description}}" [required]="item.isRequired && item.isVisible"></angular2-multiselect>
+    <input *ngSwitchCase="'number'"  name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="number" placeholder="{{item.prompt}}" title="{{item.description}}" min="{{item.min}}" max="{{item.max}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+    <div *ngSwitchCase="'file'">
+
+      <label class="dynamicFileName" for="dynamicFileInput-{{item.name}}">
+        <input id="dynamicFileInput-{{item.name}}"  name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="file" placeholder="{{item.prompt}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+        <label for="dynamicFileInput-{{item.name}}" class="labelForImage">
+          <span class="icon-browse"></span>
+        </label>
+      </label>
+    </div>
+    <input *ngSwitchCase="'checkbox'"  name="{{item.name}}" [formControlName]="item.name" type="checkbox"  data-toggle="toggle" title="{{item.description}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+    <input *ngSwitchDefault name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" placeholder="{{item.prompt}}" title="{{item.description}}" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible"/>
+  </div>
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.scss b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.scss
new file mode 100644
index 0000000..11a1414
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/dynamic-inputs/dynamic-inputs.scss
@@ -0,0 +1,58 @@
+input[type=file] {
+  opacity: 0;
+  position: relative;
+  z-index: 1;
+  width: 0.5px;
+  height: 0.5px;
+  display: inline-block;
+  input {
+    display: none;
+  }
+}
+
+.dynamicFileName {
+  width: 100%;
+  height: 34px;
+  background: #FFFFFF;
+  border: 1px solid #D2D2D2;
+  border-radius: 2px;
+  display: inline-block;
+  line-height: 34px;
+  font-weight: normal !important;
+  padding-left: 3px;
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+
+.labelForImage {
+  background: #F2F2F2;
+  border-left: 1px solid #D2D2D2;
+  float: right;
+  height: 32px;
+}
+
+.icon-browse:before {
+  content: "\e90d";
+  color: #5A5A5A;
+  font-size: 15px;
+  cursor: pointer;
+  width: 34px;
+  height: 100%;
+  line-height: 34px;
+  text-align: center;
+  display: inline-block;
+  vertical-align: super;
+  border-radius: 2px;
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+
+.icon-browse:hover::before {
+  background-color: #E6F6FB;
+  color: #009FDB;
+}
+
+.icon-browse:active::before {
+  background-color: #E6F6FB;
+  color: #009FDB;
+}