summaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/directives/select-property-types
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/directives/select-property-types')
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html81
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less117
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts184
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html56
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less85
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts108
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html56
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less83
-rw-r--r--catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts139
9 files changed, 909 insertions, 0 deletions
diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html
new file mode 100644
index 0000000000..8560e66978
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.html
@@ -0,0 +1,81 @@
+<div class="data-type-fields-structure">
+ <div class="open-close">
+ <div class="open-close-button" data-ng-class="{'expand':expand,'collapse':!expand}"
+ data-ng-click="expandAndCollapse()"></div>
+ <span class="data-type-name">{{typeName.replace("org.openecomp.datatypes.heat.","")}}</span>
+ </div>
+ <div data-ng-show="expand" data-ng-repeat="property in dataTypeProperties" class="property" data-ng-init="property.isAlreadyInput = isAlreadyInput(property)">
+
+ <sdc-radio-button sdc-model="dataTypesService.selectedPropertiesName" value="{{path + '#' + property.name}}" data-ng-if="path && !property.isAlreadyInput"
+ disabled="false" elem-name="selectedPropertiesName" elem-id="{{path + '#' + property.name}}" class="selectPropertyType"
+ on-value-change="setSelectedType(property)" data-tests-id="propertyRadioButton_{{property.name}}"></sdc-radio-button>
+ <div class="existInputContainer" data-ng-if="property.isAlreadyInput"><span class="existInput"></span></div>
+ <div class="i-sdc-form-item property-name">
+ <div tooltips tooltip-content="{{property.name}}">
+ <input class="i-sdc-form-input"
+ type="text"
+ data-ng-disabled="true"
+ value="{{property.name}}"/>
+ </div>
+ </div>
+ <div data-ng-if="dataTypesService.isDataTypeForDataTypePropertyType(property)" class="inner-structure">
+ <select-fields-structure value-obj-ref="(valueObjRef[property.name])"
+ type-name="property.type"
+ parent-form-obj="parentFormObj"
+ fields-prefix-name="fieldsPrefixName+property.name"
+ read-only="readOnly"
+ default-value="{{currentTypeDefaultValue[property.name]}}"
+ path="{{path + '#' + property.name}}"
+ is-parent-already-input="isParentAlreadyInput"
+ ></select-fields-structure>
+
+ </div>
+ <div data-ng-if="!dataTypesService.isDataTypeForDataTypePropertyType(property)" ng-switch="property.type">
+ <div ng-switch-when="map">
+ <select-type-map value-obj-ref="valueObjRef[property.name]"
+ schema-property="property.schema.property"
+ parent-form-obj="parentFormObj"
+ fields-prefix-name="fieldsPrefixName+property.name"
+ read-only="readOnly"
+ default-value="{{currentTypeDefaultValue[property.name]}}"
+ ></select-type-map>
+ </div>
+ <div ng-switch-when="list">
+ <select-type-list value-obj-ref="valueObjRef[property.name]"
+ schema-property="property.schema.property"
+ parent-form-obj="parentFormObj"
+ fields-prefix-name="fieldsPrefixName+property.name"
+ read-only="readOnly"
+ default-value="{{currentTypeDefaultValue[property.name]}}"
+ ></select-type-list>
+ </div>
+ <div ng-switch-default class="primitive-value-field">
+ <div class="i-sdc-form-item"
+ data-ng-class="{error:(parentFormObj[fieldsPrefixName+property.name].$dirty && parentFormObj[fieldsPrefixName+property.name].$invalid)}">
+ <input class="i-sdc-form-input"
+ data-tests-id="{{fieldsPrefixName+property.name}}"
+ ng-if="!((property.simpleType||property.type) == 'boolean')"
+ data-ng-maxlength="100"
+ data-ng-disabled="readOnly"
+ maxlength="100"
+ data-ng-model="valueObjRef[property.name]"
+ type="text"
+ name="{{fieldsPrefixName+property.name}}"
+ data-ng-model-options="{ debounce: 200 }"
+ data-ng-change="!parentFormObj[fieldsPrefixName+property.name].$error.pattern && ('integer'==property.type && parentFormObj[fieldsPrefixName+property.name].$setValidity('pattern', validateIntRange(valueObjRef[property.name])) || onValueChange(property.name, (property.simpleType||property.type)))"
+ autofocus/>
+ <select class="i-sdc-form-select"
+ data-tests-id="{{fieldsPrefixName+property.name}}"
+ ng-if="(property.simpleType||property.type) == 'boolean'"
+ data-ng-disabled="readOnly"
+ name="{{fieldsPrefixName+property.name}}"
+ data-ng-change="onValueChange(property.name,'boolean')"
+ data-ng-model="valueObjRef[property.name]"
+ data-ng-options="option.v as option.n for option in [{ n: '', v: undefined }, { n: 'false', v: false }, { n: 'true', v: true }]">
+ </select>
+
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less
new file mode 100644
index 0000000000..43d2d646a1
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.less
@@ -0,0 +1,117 @@
+
+.selectPropertyType {
+ .tlv-radio-label {
+ margin-top: -7px;
+ }
+}
+
+.data-type-fields-structure {
+ background-color: @tlv_color_v;
+ padding: 10px;
+ display: table-caption;
+ .open-close {
+ position: relative;
+ .open-close-button {
+ position: absolute;
+ top: 50%;
+ margin-top: -7px;
+ &.expand {
+ .sprite-new;
+ .expand-collapse-minus-icon;
+ }
+ &.collapse {
+ .sprite-new;
+ .expand-collapse-plus-icon;
+ }
+ }
+
+ }
+
+ .existInputContainer {
+ height: 30px;
+ width: 20px;
+ position: relative;
+ }
+ .existInput {
+ .sprite-new;
+ .sdc-success;
+ position: absolute;
+ top: 18px;
+ left: 3px;
+ }
+
+ .data-type-name {
+ .m_16_m;
+ margin-left: 22px;
+ }
+
+ .i-sdc-form-input:disabled{
+ .disabled;
+ &[type="text"]{
+ opacity: 1 !important;
+ background-color: @tlv_color_t;
+ color:black;
+ }
+ }
+
+ .property {
+ display: flex;
+ min-width: 365px;
+ min-height: 46px;
+ input[type="text"], select {
+ width: 170px;
+ }
+ .property-name {
+ float: left;
+ margin-top: 8px;
+ }
+ .primitive-value-field {
+ float: right;
+ margin-top: 8px;
+ margin-left: 10px;
+ }
+ .inner-structure {
+ display: -webkit-box;
+ }
+ }
+
+ [ng-switch-when="map"] {
+ margin-top: 8px;
+ margin-left: 10px;
+ .map-item {
+ border: solid 1px @main_color_o;
+ min-width: 401px;
+ min-height: 69px;
+ float: none !important;
+ }
+ .add-map-item {
+ width: auto;
+ float: none;
+ &:nth-child(1) {
+ position: relative;
+ top: 6px;
+ }
+ .add-btn {
+ float: none;
+ }
+ }
+
+ }
+
+ [ng-switch-when="list"] {
+ float: left;
+ margin-top: 8px;
+ margin-left: 10px;
+ min-width: 280px;
+ .dt-list-item {
+ border: solid 1px @main_color_o;
+ }
+ .list-value-items {
+ width: 280px;
+ }
+ }
+}
+
+
+
+
diff --git a/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts
new file mode 100644
index 0000000000..aee4b3b6af
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-data-type-fields-structure/select-data-type-fields-structure.ts
@@ -0,0 +1,184 @@
+/**
+ * Created by obarda on 1/27/2016.
+ */
+'use strict';
+import {ValidationUtils} from "app/utils";
+import { DataTypesService } from "app/services";
+import { DataTypePropertyModel } from "app/models/data-type-properties";
+import {DataTypesMap, PropertyModel} from "app/models";
+
+export interface ISelectDataTypeFieldsStructureScope extends ng.IScope {
+ parentFormObj:ng.IFormController;
+ dataTypeProperties:Array<DataTypePropertyModel>;
+ typeName:string;
+ valueObjRef:any;
+ propertyNameValidationPattern:RegExp;
+ fieldsPrefixName:string;
+ readOnly:boolean;
+ currentTypeDefaultValue:any;
+ types:DataTypesMap;
+ expandByDefault:boolean;
+ expand:boolean;
+ expanded:boolean;
+ dataTypesService:DataTypesService;
+ path:string;
+ isParentAlreadyInput:boolean;
+
+ expandAndCollapse():void;
+ getValidationPattern(type:string):RegExp;
+ validateIntRange(value:string):boolean;
+ isAlreadyInput(property:PropertyModel):boolean;
+ setSelectedType(property:PropertyModel):void;
+ onValueChange(propertyName:string, type:string):void;
+}
+
+
+export class SelectDataTypeFieldsStructureDirective implements ng.IDirective {
+
+ constructor(private DataTypesService:DataTypesService,
+ private PropertyNameValidationPattern:RegExp,
+ private ValidationUtils:ValidationUtils) {
+ }
+
+ scope = {
+ valueObjRef: '=',
+ typeName: '=',
+ parentFormObj: '=',
+ fieldsPrefixName: '=',
+ readOnly: '=',
+ defaultValue: '@',
+ expandByDefault: '=',
+ path: '@',
+ isParentAlreadyInput: '='
+ };
+
+ restrict = 'E';
+ replace = true;
+ template = ():string => {
+ return require('./select-data-type-fields-structure.html');
+ };
+ // public types=Utils.Constants.PROPERTY_DATA.TYPES;
+
+ //get data type properties array and return object with the properties and their default value
+ //(for example: get: [{name:"prop1",defaultValue:1 ...},{name:"prop2", defaultValue:"bla bla" ...}]
+ // return: {prop1: 1, prop2: "bla bla"}
+ private getDefaultValue = (dataTypeProperties:Array<DataTypePropertyModel>):any => {
+ let defaultValue = {};
+ for (let i = 0; i < dataTypeProperties.length; i++) {
+ if (dataTypeProperties[i].type != 'string') {
+ if (!angular.isUndefined(dataTypeProperties[i].defaultValue)) {
+ defaultValue[dataTypeProperties[i].name] = JSON.parse(dataTypeProperties[i].defaultValue);
+ }
+ } else {
+ defaultValue[dataTypeProperties[i].name] = dataTypeProperties[i].defaultValue;
+ }
+ }
+ return defaultValue;
+ };
+
+ private initDataOnScope = (scope:ISelectDataTypeFieldsStructureScope, $attr:any):void => {
+ scope.dataTypesService = this.DataTypesService;
+ scope.dataTypeProperties = angular.copy(this.DataTypesService.getFirsLevelOfDataTypeProperties(scope.typeName));
+ if ($attr.defaultValue) {
+ scope.currentTypeDefaultValue = JSON.parse($attr.defaultValue);
+ } else {
+ scope.currentTypeDefaultValue = this.getDefaultValue(scope.dataTypeProperties);
+ }
+
+ if (!scope.valueObjRef) {
+ scope.valueObjRef = {};
+ }
+
+ _.forEach(scope.currentTypeDefaultValue, (value, key)=> {
+ if (angular.isUndefined(scope.valueObjRef[key])) {
+ if (typeof scope.currentTypeDefaultValue[key] == 'object') {
+ angular.copy(scope.currentTypeDefaultValue[key], scope.valueObjRef[key]);
+ } else {
+ scope.valueObjRef[key] = scope.currentTypeDefaultValue[key];
+ }
+ }
+ });
+ };
+
+ private rerender = (scope:any):void => {
+ scope.expanded = false;
+ scope.expand = false;
+ if (scope.expandByDefault) {
+ scope.expandAndCollapse();
+ }
+ };
+
+ link = (scope:ISelectDataTypeFieldsStructureScope, element:any, $attr:any) => {
+ scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
+
+ scope.$watchCollection('[typeName,fieldsPrefixName]', (newData:any):void => {
+ this.rerender(scope);
+ });
+
+
+ scope.expandAndCollapse = ():void => {
+ if (!scope.expanded) {
+ this.initDataOnScope(scope, $attr);
+ scope.expanded = true;
+ }
+ scope.expand = !scope.expand;
+ };
+
+ scope.getValidationPattern = (type:string):RegExp => {
+ return this.ValidationUtils.getValidationPattern(type);
+ };
+
+ scope.validateIntRange = (value:string):boolean => {
+ return !value || this.ValidationUtils.validateIntRange(value);
+ };
+
+ /*
+ check if property is alrady declered on the service by meatching the input name & the property name
+
+ */
+ scope.isAlreadyInput = (property:PropertyModel):boolean => {
+ if (scope.path) {
+ if (scope.isParentAlreadyInput) {
+ return true;
+ }
+ let parentInputName = this.DataTypesService.selectedInstance.normalizedName + '_' + scope.path.replace('#', '_');// set the input parent as he need to declared as input
+ let inputName = parentInputName + '_' + property.name;// set the input name as he need to declared as input
+ let selectedProperty = _.find(this.DataTypesService.selectedComponentInputs, (componentInput)=> {
+ if (componentInput.name == parentInputName) { //check if the parent(all the complex) is already declared
+ scope.isParentAlreadyInput = true;
+ return true;
+ } else if (componentInput.name.substring(0, inputName.length) == inputName) { //check if specific property inside the complex
+ return true;
+ }
+ //return componentInput.name == parentInputName || componentInput.name.substring(0,inputName.length) == inputName;//check if the parent(all the complex) is already declared or specific property inside the complex
+ });
+ if (selectedProperty) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ scope.setSelectedType = (property:PropertyModel):void=> {
+ scope.dataTypesService.selectedInput = property;
+ scope.dataTypesService.selectedPropertiesName = scope.path + '#' + property.name;
+ };
+
+ scope.onValueChange = (propertyName:string, type:string):void => {
+ scope.valueObjRef[propertyName] = !angular.isUndefined(scope.valueObjRef[propertyName]) ? scope.valueObjRef[propertyName] : scope.currentTypeDefaultValue[propertyName];
+ if (scope.valueObjRef[propertyName] && type != 'string') {
+ scope.valueObjRef[propertyName] = JSON.parse(scope.valueObjRef[propertyName]);
+ }
+ };
+
+
+ };
+
+ public static factory = (DataTypesService:DataTypesService,
+ PropertyNameValidationPattern:RegExp,
+ ValidationUtils:ValidationUtils)=> {
+ return new SelectDataTypeFieldsStructureDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils);
+ };
+}
+
+SelectDataTypeFieldsStructureDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils'];
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html
new file mode 100644
index 0000000000..f439147301
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.html
@@ -0,0 +1,56 @@
+<div>
+ <div data-ng-if="!isSchemaTypeDataType">
+ <div class="i-sdc-form-item list-new-item" data-ng-class="{error:(parentFormObj['listNewItem'+fieldsPrefixName].$dirty && parentFormObj['listNewItem'+fieldsPrefixName].$invalid)}">
+ <input class="i-sdc-form-input"
+ data-tests-id="listNewItem{{fieldsPrefixName}}"
+ ng-if="!((schemaProperty.simpleType||schemaProperty.type) == 'boolean')"
+ data-ng-disabled="readOnly"
+ data-ng-model="listNewItem.value"
+ type="text"
+ name="listNewItem{{fieldsPrefixName}}"
+ data-ng-model-options="{ debounce: 200 }"
+ placeholder="Type a value and then click ADD"
+ data-ng-maxlength="maxLength"
+ maxlength="{{maxLength}}"
+ sdc-keyboard-events="" key-enter="schemaProperty.type && !parentFormObj['listNewItem'+fieldsPrefixName].$invalid && listNewItem.value && addListItem"
+ autofocus />
+ <select class="i-sdc-form-select"
+ data-tests-id="listNewItem{{fieldsPrefixName}}"
+ ng-if="(schemaProperty.simpleType||schemaProperty.type) == 'boolean'"
+ data-ng-disabled="readOnly"
+ name="listNewItem{{fieldsPrefixName}}"
+ data-ng-model="listNewItem.value">
+ <option value="true">true</option>
+ <option value="false">false</option>
+ </select>
+ <div class="input-error" data-ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$dirty && parentFormObj['listNewItem'+fieldsPrefixName].$invalid">
+ <span ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$error.pattern" translate="PROPERTY_EDIT_PATTERN"></span>
+ <span ng-show="parentFormObj['listNewItem'+fieldsPrefixName].$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '{{maxLength}}' }"></span>
+ </div>
+ </div>
+ <!--<div class="add-btn add-list-item" data-tests-id="add-list-item{{fieldsPrefixName}}"-->
+ <!--data-ng-class="{'disabled': readOnly || !schemaProperty.type || parentFormObj['listNewItem'+fieldsPrefixName].$invalid || !listNewItem.value}" data-ng-click="addListItem()">Add</div>-->
+ <div class="list-value-items">
+ <span class="list-value-item" data-ng-repeat="value in valueObjRef track by $index">
+ {{value}}
+ <span ng-if="!readOnly" class="delete-list-item sprite-new small-x-button" data-ng-click="deleteListItem($index)"></span>
+ </span>
+ </div>
+ </div>
+ <div data-ng-if="isSchemaTypeDataType">
+ <div class="dt-list">
+ <div data-ng-repeat="value in valueObjRef track by $index" class="dt-list-item">
+ <select-fields-structure value-obj-ref="valueObjRef[$index]"
+ type-name="schemaProperty.type"
+ parent-form-obj="parentFormObj"
+ fields-prefix-name="fieldsPrefixName+''+$index"
+ read-only="readOnly">
+ <!--path="{{path}}"-->
+ </select-fields-structure>
+ </div>
+ <!--<div class="add-btn add-list-item" data-tests-id="add-list-item"-->
+ <!--data-ng-class="{'disabled': readOnly}" data-ng-click="listNewItem.value='{}';addListItem();">Add</div>-->
+ </div>
+
+ </div>
+</div>
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less
new file mode 100644
index 0000000000..71263f2642
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.less
@@ -0,0 +1,85 @@
+.list-new-item{
+ float: left;
+ width: 50%;
+ min-width: 221px;
+ margin-right: 15px;
+ input{
+ min-width: 221px;
+ }
+}
+
+.list-value-items{
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ border: 1px solid @main_color_o;
+ padding-bottom: 10px;
+ min-height: 100px;
+ clear: both;
+ background-color: white;
+ .list-value-item{
+ display: inline-block;
+ background-color: @tlv_color_v;
+ margin: 10px 0 0 10px;
+ padding: 0 8px;
+ .delete-list-item{
+ margin: 0 0 0 2px;
+ .hand;
+ }
+ }
+}
+
+.add-btn {
+ .f-color.a;
+ .f-type._14_m;
+ .hand;
+
+ &.add-list-item {
+ float: left;
+ margin-top: 5px;
+ width: 44px;
+ }
+
+ &:before {
+ .sprite-new;
+ .plus-icon;
+ margin-right: 5px;
+ content: "";
+
+ }
+ &:hover {
+ .f-color.b;
+ &:before {
+ .sprite-new;
+ .plus-icon-hover;
+ }
+ }
+
+}
+
+.dt-list{
+ display: table-caption;
+ .dt-list-item {
+ border-radius: 3px;
+ background-color: @tlv_color_v;
+ display: inline-block;
+ .delete-dt-list-item{
+ float: right;
+ position: relative;
+ top: 5px;
+ right: 5px;
+ .sprite-new;
+ .delete-icon;
+ &:hover{
+ .delete-icon-hover;
+ }
+ }
+ .data-type-name{
+ margin-right: 16px;
+ }
+ }
+ &>.add-list-item{
+ float:none;
+ }
+}
+
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts
new file mode 100644
index 0000000000..d277040798
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-list/select-type-list-directive.ts
@@ -0,0 +1,108 @@
+/**
+ * Created by rcohen on 9/15/2016.
+ */
+'use strict';
+import {DataTypesService} from "app/services/data-types-service";
+import {SchemaProperty} from "app/models/aschema-property";
+import {ValidationUtils, PROPERTY_TYPES} from "app/utils";
+
+export interface ISelectTypeListScope extends ng.IScope {
+ parentFormObj:ng.IFormController;
+ schemaProperty:SchemaProperty;
+ isSchemaTypeDataType:boolean;
+ valueObjRef:any;
+ propertyNameValidationPattern:RegExp;
+ fieldsPrefixName:string;
+ readOnly:boolean;
+ listDefaultValue:any;
+ listNewItem:any;
+ maxLength:number;
+ dataTypesService:DataTypesService;
+
+ getValidationPattern(type:string):RegExp;
+ validateIntRange(value:string):boolean;
+ addListItem():void;
+ deleteListItem(listItemIndex:number):void
+}
+
+export class SelectTypeListDirective implements ng.IDirective {
+
+ constructor(private DataTypesService:DataTypesService,
+ private PropertyNameValidationPattern:RegExp,
+ private ValidationUtils:ValidationUtils) {
+ }
+
+ scope = {
+ valueObjRef: '=',//ref to list object in the parent value object
+ schemaProperty: '=',//get the schema.property object
+ parentFormObj: '=',//ref to parent form (get angular form object)
+ fieldsPrefixName: '=',//prefix for form fields names
+ readOnly: '=',//is form read only
+ defaultValue: '@',//this list default value
+ maxLength: '=',
+ path: '@'
+ };
+
+ restrict = 'E';
+ replace = true;
+ template = ():string => {
+ return require('./select-type-list-directive.html');
+ };
+
+ link = (scope:ISelectTypeListScope, element:any, $attr:any) => {
+ scope.dataTypesService = this.DataTypesService;
+ scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
+
+ //reset valueObjRef when schema type is changed
+ scope.$watchCollection('schemaProperty.type', (newData:any):void => {
+ scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
+ //insert 1 empty item dt by default
+ if (scope.isSchemaTypeDataType && (!scope.valueObjRef || !scope.valueObjRef.length)) {
+ scope.valueObjRef = scope.valueObjRef || [];
+ scope.valueObjRef.push({});
+ }
+ });
+
+ //when user brows between properties in "edit property form"
+ scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
+ scope.listNewItem = {value: ''};
+
+ if ($attr.defaultValue) {
+ scope.listDefaultValue = JSON.parse($attr.defaultValue);
+ }
+ });
+
+ scope.getValidationPattern = (type:string):RegExp => {
+ return this.ValidationUtils.getValidationPattern(type);
+ };
+
+ scope.validateIntRange = (value:string):boolean => {
+ return !value || this.ValidationUtils.validateIntRange(value);
+ };
+
+ scope.addListItem = ():void => {
+ scope.valueObjRef = scope.valueObjRef || [];
+ let newVal = ((scope.schemaProperty.simpleType || scope.schemaProperty.type) == PROPERTY_TYPES.STRING ? scope.listNewItem.value : JSON.parse(scope.listNewItem.value));
+ scope.valueObjRef.push(newVal);
+ scope.listNewItem.value = "";
+ };
+
+ scope.deleteListItem = (listItemIndex:number):void => {
+ scope.valueObjRef.splice(listItemIndex, 1);
+ if (!scope.valueObjRef.length) {
+ if (scope.listDefaultValue) {
+ angular.copy(scope.listDefaultValue, scope.valueObjRef);
+ }
+ }
+ };
+ };
+
+ public static factory = (DataTypesService:DataTypesService,
+ PropertyNameValidationPattern:RegExp,
+ ValidationUtils:ValidationUtils)=> {
+ return new SelectTypeListDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils);
+ };
+}
+
+SelectTypeListDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils'];
+
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html
new file mode 100644
index 0000000000..a56428e5c2
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.html
@@ -0,0 +1,56 @@
+<div>
+ <div data-ng-repeat="i in getNumber(mapKeys.length) track by $index" class="map-item" data-ng-class="{'primitive-value-map':!isSchemaTypeDataType}">
+ <div class="i-sdc-form-item map-item-field" data-ng-class="{error:(parentFormObj['mapKey'+fieldsPrefixName+$index].$dirty && parentFormObj['mapKey'+fieldsPrefixName+$index].$invalid)}">
+ <label class="i-sdc-form-label required">Key</label>
+ <input class="i-sdc-form-input"
+ data-tests-id="mapKey{{fieldsPrefixName}}{{$index}}"
+ data-ng-model="mapKeys[$index]"
+ type="text"
+ data-ng-maxlength="50"
+ maxlength="50"
+ name="mapKey{{fieldsPrefixName}}{{$index}}"
+ data-ng-model-options="{ debounce: 200 }"
+ data-ng-change="changeKeyOfMap(mapKeys[$index], $index,'mapKey'+fieldsPrefixName+$index);$event.stopPropagation();"
+ data-ng-disabled="readOnly"
+ data-required
+ autofocus/>
+ </div>
+ <div data-ng-if="!isSchemaTypeDataType" class="i-sdc-form-item map-item-field" data-ng-class="{error:(parentFormObj['mapValue'+fieldsPrefixName+$index].$dirty && parentFormObj['mapValue'+fieldsPrefixName+$index].$invalid)}">
+ <label class="i-sdc-form-label required">Value</label>
+ <input class="i-sdc-form-input"
+ ng-if="!((schemaProperty.simpleType||schemaProperty.type) == 'boolean')"
+ data-ng-disabled="readOnly"
+ data-ng-model="valueObjRef[mapKeys[$index]]"
+ type="text"
+ name="mapValue{{fieldsPrefixName}}{{$index}}"
+ data-tests-id="mapValue{{fieldsPrefixName}}{{$index}}"
+ data-ng-change="!parentFormObj['mapValue'+fieldsPrefixName+$index].$error.pattern && parseToCorrectType(valueObjRef, key, (schemaProperty.simpleType||schemaProperty.type))"
+ data-ng-model-options="{ debounce: 200 }"
+ data-ng-maxlength="maxLength"
+ maxlength="{{maxLength}}"
+ data-required
+ autofocus />
+ <select class="i-sdc-form-select"
+ data-tests-id="mapValue{{fieldsPrefixName}}{{$index}}"
+ ng-if="(schemaProperty.simpleType||schemaProperty.type) == 'boolean'"
+ data-ng-disabled="readOnly"
+ name="mapValue{{fieldsPrefixName}}{{$index}}"
+ data-ng-model="valueObjRef[mapKeys[$index]]"
+ data-required>
+ <option value="true">true</option>
+ <option value="false">false</option>
+ </select>
+ </div>
+ <div data-ng-if="isSchemaTypeDataType" class="i-sdc-form-item map-item-field">
+ <label class="i-sdc-form-label">Value</label>
+ <select-fields-structure value-obj-ref="valueObjRef[mapKeys[$index]]"
+ type-name="schemaProperty.type"
+ parent-form-obj="parentFormObj"
+ fields-prefix-name="'mapValue'+fieldsPrefixName+''+$index"
+ read-only="readOnly">
+ <!--path="{{path + '#' + mapKeys[$index]}}"-->
+ </select-fields-structure>
+ </div>
+ </div>
+</div>
+
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less
new file mode 100644
index 0000000000..2480b626f2
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.less
@@ -0,0 +1,83 @@
+.add-map-item{
+ &:nth-child(odd){
+ float: right;
+ }
+ &:nth-child(1){
+ float: none;
+ .add-btn{
+ float: none;
+ }
+ }
+ width: 400px;
+ .add-btn{
+ width: 44px;
+ float: right;
+ }
+ &.schema-data-type{
+ float:none;
+ .add-btn{
+ float: none;
+ }
+ }
+}
+
+.add-btn {
+ .f-color.a;
+ .f-type._14_m;
+ .hand;
+
+ &:before {
+ .sprite-new;
+ .plus-icon;
+ margin-right: 5px;
+ content: "";
+
+ }
+ &:hover {
+ .f-color.b;
+ &:before {
+ .sprite-new;
+ .plus-icon-hover;
+ }
+ }
+
+}
+
+.map-item{
+ min-width: 389px;
+ min-height: 65px;
+ background-color: @tlv_color_v;
+ border-radius: 3px;
+ margin-bottom: 8px;
+ float: left;
+ display: flex;
+ &:nth-child(even).primitive-value-map{
+ float: right;
+ }
+ .delete-map-item {
+ float: right;
+ position: relative;
+ top: 5px;
+ right: 5px;
+ .sprite-new;
+ .delete-icon;
+ &:hover{
+ .delete-icon-hover;
+ }
+ }
+ .map-item-field {
+ margin: 7px 12px !important;
+ float: left;
+ min-width: 170px;
+ min-height: 50px;
+ select{
+ width:171px;
+ }
+ input[type="text"]{
+ width: 170px;
+ }
+ &>.data-type-fields-structure{
+ padding: 0;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts
new file mode 100644
index 0000000000..19df8dfb71
--- /dev/null
+++ b/catalog-ui/src/app/directives/select-property-types/select-type-map/select-type-map-directive.ts
@@ -0,0 +1,139 @@
+/**
+ * Created by rcohen on 9/15/2016.
+ */
+'use strict';
+import {SchemaProperty} from "app/models";
+import {DataTypesService} from "app/services";
+import {ValidationUtils, PROPERTY_TYPES} from "app/utils";
+
+export interface ISelectTypeMapScope extends ng.IScope {
+ parentFormObj:ng.IFormController;
+ schemaProperty:SchemaProperty;
+ isSchemaTypeDataType:boolean;
+ valueObjRef:any;
+ mapKeys:Array<string>;//array of map keys
+ MapKeyValidationPattern:RegExp;
+ fieldsPrefixName:string;
+ readOnly:boolean;
+ mapDefaultValue:any;
+ maxLength:number;
+ dataTypesService:DataTypesService;
+
+ getValidationPattern(type:string):RegExp;
+ validateIntRange(value:string):boolean;
+ changeKeyOfMap(newKey:string, index:number, fieldName:string):void;
+ deleteMapItem(index:number):void;
+ addMapItemFields():void;
+ parseToCorrectType(objectOfValues:any, locationInObj:string, type:string):void;
+ getNumber(num:number):Array<any>;
+}
+
+
+export class SelectTypeMapDirective implements ng.IDirective {
+
+ constructor(private DataTypesService:DataTypesService,
+ private MapKeyValidationPattern:RegExp,
+ private ValidationUtils:ValidationUtils,
+ private $timeout:ng.ITimeoutService) {
+ }
+
+ scope = {
+ valueObjRef: '=',//ref to map object in the parent value object
+ schemaProperty: '=',//get the schema.property object
+ parentFormObj: '=',//ref to parent form (get angular form object)
+ fieldsPrefixName: '=',//prefix for form fields names
+ readOnly: '=',//is form read only
+ defaultValue: '@',//this map default value
+ maxLength: '=',
+ path: '@'
+ };
+
+ restrict = 'E';
+ replace = true;
+ template = ():string => {
+ return require('./select-type-map-directive.html');
+ };
+
+ link = (scope:ISelectTypeMapScope, element:any, $attr:any) => {
+
+ scope.dataTypesService = this.DataTypesService;
+ scope.MapKeyValidationPattern = this.MapKeyValidationPattern;
+
+ //reset valueObjRef and mapKeys when schema type is changed
+ scope.$watchCollection('schemaProperty.type', (newData:any):void => {
+ scope.isSchemaTypeDataType = this.DataTypesService.isDataTypeForSchemaType(scope.schemaProperty);
+ if (scope.valueObjRef) {
+ scope.mapKeys = Object.keys(scope.valueObjRef);
+ }
+ });
+
+ //when user brows between properties in "edit property form"
+ scope.$watchCollection('fieldsPrefixName', (newData:any):void => {
+ if (!scope.valueObjRef) {
+ scope.valueObjRef = {};
+ }
+ scope.mapKeys = Object.keys(scope.valueObjRef);
+
+ if ($attr.defaultValue) {
+ scope.mapDefaultValue = JSON.parse($attr.defaultValue);
+ }
+ });
+
+ //return dummy array in order to prevent rendering map-keys ng-repeat again when a map key is changed
+ scope.getNumber = (num:number):Array<any> => {
+ return new Array(num);
+ };
+
+ scope.getValidationPattern = (type:string):RegExp => {
+ return this.ValidationUtils.getValidationPattern(type);
+ };
+
+ scope.validateIntRange = (value:string):boolean => {
+ return !value || this.ValidationUtils.validateIntRange(value);
+ };
+
+ scope.changeKeyOfMap = (newKey:string, index:number, fieldName:string):void => {
+ let oldKey = Object.keys(scope.valueObjRef)[index];
+ let existsKeyIndex = Object.keys(scope.valueObjRef).indexOf(newKey);
+ if (existsKeyIndex > -1 && existsKeyIndex != index) {
+ scope.parentFormObj[fieldName].$setValidity('keyExist', false);
+ } else {
+ scope.parentFormObj[fieldName].$setValidity('keyExist', true);
+ if (!scope.parentFormObj[fieldName].$invalid) {
+ angular.copy(JSON.parse(JSON.stringify(scope.valueObjRef).replace('"' + oldKey + '":', '"' + newKey + '":')), scope.valueObjRef);//update key
+ }
+ }
+ };
+
+ scope.deleteMapItem = (index:number):void=> {
+ delete scope.valueObjRef[scope.mapKeys[index]];
+ scope.mapKeys.splice(index, 1);
+ if (!scope.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default
+ if (scope.mapDefaultValue) {
+ angular.copy(scope.mapDefaultValue, scope.valueObjRef);
+ scope.mapKeys = Object.keys(scope.valueObjRef);
+ }
+ }
+ };
+
+ scope.addMapItemFields = ():void => {
+ scope.valueObjRef[''] = null;
+ scope.mapKeys = Object.keys(scope.valueObjRef);
+ };
+
+ scope.parseToCorrectType = (objectOfValues:any, locationInObj:string, type:string):void => {
+ if (objectOfValues[locationInObj] && type != PROPERTY_TYPES.STRING) {
+ objectOfValues[locationInObj] = JSON.parse(objectOfValues[locationInObj]);
+ }
+ }
+ };
+
+ public static factory = (DataTypesService:DataTypesService,
+ MapKeyValidationPattern:RegExp,
+ ValidationUtils:ValidationUtils,
+ $timeout:ng.ITimeoutService)=> {
+ return new SelectTypeMapDirective(DataTypesService, MapKeyValidationPattern, ValidationUtils, $timeout);
+ };
+}
+
+SelectTypeMapDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'MapKeyValidationPattern', 'ValidationUtils', '$timeout'];