diff options
Diffstat (limited to 'catalog-ui/src/app/view-models/forms/property-forms/component-property-form')
2 files changed, 523 insertions, 0 deletions
diff --git a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts new file mode 100644 index 0000000000..b3557b055f --- /dev/null +++ b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts @@ -0,0 +1,322 @@ +'use strict'; +import { + PROPERTY_TYPES, ModalsHandler, ValidationUtils, PROPERTY_VALUE_CONSTRAINTS, FormState, PROPERTY_DATA} from "app/utils"; +import {DataTypesService} from "app/services"; +import {PropertyModel, DataTypesMap, Component} from "app/models"; + +export interface IEditPropertyModel { + property:PropertyModel; + types:Array<string>; + simpleTypes:Array<string>; +} + +interface IPropertyFormViewModelScope extends ng.IScope { + forms:any; + editForm:ng.IFormController; + footerButtons:Array<any>; + isNew:boolean; + isLoading:boolean; + isService:boolean; + validationPattern:RegExp; + propertyNameValidationPattern:RegExp; + commentValidationPattern:RegExp; + editPropertyModel:IEditPropertyModel; + modalInstanceProperty:ng.ui.bootstrap.IModalServiceInstance; + currentPropertyIndex:number; + isLastProperty:boolean; + myValue:any; + nonPrimitiveTypes:Array<string>; + dataTypes:DataTypesMap; + isTypeDataType:boolean; + maxLength:number; + isPropertyValueOwner:boolean; + + validateJson(json:string):boolean; + save(doNotCloseModal?:boolean):void; + getValidationPattern(type:string):RegExp; + validateIntRange(value:string):boolean; + close():void; + onValueChange():void; + onSchemaTypeChange():void; + onTypeChange(resetSchema:boolean):void; + showSchema():boolean; + delete(property:PropertyModel):void; + getPrev():void; + getNext():void; + isSimpleType(typeName:string):boolean; + getDefaultValue():any; +} + +export class PropertyFormViewModel { + + static '$inject' = [ + '$scope', + 'Sdc.Services.DataTypesService', + '$uibModalInstance', + 'property', + 'ValidationPattern', + 'PropertyNameValidationPattern', + 'CommentValidationPattern', + 'ValidationUtils', + 'component', + '$filter', + 'ModalsHandler', + 'filteredProperties', + '$timeout', + 'isPropertyValueOwner' + ]; + + private formState:FormState; + + constructor(private $scope:IPropertyFormViewModelScope, + private DataTypesService:DataTypesService, + private $uibModalInstance:ng.ui.bootstrap.IModalServiceInstance, + private property:PropertyModel, + private ValidationPattern:RegExp, + private PropertyNameValidationPattern:RegExp, + private CommentValidationPattern:RegExp, + private ValidationUtils:ValidationUtils, + private component:Component, + private $filter:ng.IFilterService, + private ModalsHandler:ModalsHandler, + private filteredProperties:Array<PropertyModel>, + private $timeout:ng.ITimeoutService, + private isPropertyValueOwner:boolean) { + + this.formState = angular.isDefined(property.name) ? FormState.UPDATE : FormState.CREATE; + this.initScope(); + } + + private initResource = ():void => { + this.$scope.editPropertyModel.property = new PropertyModel(this.property); + this.$scope.editPropertyModel.property.type = this.property.type ? this.property.type : null; + this.setMaxLength(); + this.initAddOnLabels(); + }; + + //init property add-ons labels that show up at the left side of the input. + private initAddOnLabels = () => { + if (this.$scope.editPropertyModel.property.name == 'network_role' && this.$scope.isService) { + //the server sends back the normalized name. Remove it (to prevent interference with validation) and set the addon label to the component name directly. + //Note: this cant be done in properties.ts because we dont have access to the component + if (this.$scope.editPropertyModel.property.value) { + let splitProp = this.$scope.editPropertyModel.property.value.split(new RegExp(this.component.normalizedName + '.', "gi")); + this.$scope.editPropertyModel.property.value = splitProp.pop(); + } + this.$scope.editPropertyModel.property.addOn = this.component.name; + } + } + + private initEditPropertyModel = ():void => { + this.$scope.editPropertyModel = { + property: null, + types: PROPERTY_DATA.TYPES, + simpleTypes: PROPERTY_DATA.SIMPLE_TYPES + }; + + this.initResource(); + }; + + private initForNotSimpleType = ():void => { + let property = this.$scope.editPropertyModel.property; + this.$scope.isTypeDataType = this.DataTypesService.isDataTypeForPropertyType(this.$scope.editPropertyModel.property); + if (property.type && this.$scope.editPropertyModel.simpleTypes.indexOf(property.type) == -1) { + if (!(property.value || property.defaultValue)) { + switch (property.type) { + case PROPERTY_TYPES.MAP: + this.$scope.myValue = {'': null}; + break; + case PROPERTY_TYPES.LIST: + this.$scope.myValue = []; + break; + default: + this.$scope.myValue = {}; + } + } else { + this.$scope.myValue = JSON.parse(property.value || property.defaultValue); + } + } + }; + + private setMaxLength = ():void => { + switch (this.$scope.editPropertyModel.property.type) { + case PROPERTY_TYPES.MAP: + case PROPERTY_TYPES.LIST: + this.$scope.maxLength = this.$scope.editPropertyModel.property.schema.property.type == PROPERTY_TYPES.JSON ? + PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH : + PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH; + break; + case PROPERTY_TYPES.JSON: + this.$scope.maxLength = PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH; + break; + default: + this.$scope.maxLength =PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH; + } + }; + + + private initScope = ():void => { + + //scope properties + this.$scope.forms = {}; + this.$scope.validationPattern = this.ValidationPattern; + this.$scope.propertyNameValidationPattern = this.PropertyNameValidationPattern; + this.$scope.commentValidationPattern = this.CommentValidationPattern; + this.$scope.isLoading = false; + this.$scope.isNew = (this.formState === FormState.CREATE); + this.$scope.isService = this.component.isService(); + this.$scope.modalInstanceProperty = this.$uibModalInstance; + this.$scope.currentPropertyIndex = _.findIndex(this.filteredProperties, i=> i.name == this.property.name); + this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1); + this.$scope.dataTypes = this.DataTypesService.getAllDataTypes(); + this.$scope.isPropertyValueOwner = this.isPropertyValueOwner; + this.initEditPropertyModel(); + + this.$scope.nonPrimitiveTypes = _.filter(Object.keys(this.$scope.dataTypes), (type:string)=> { + return this.$scope.editPropertyModel.types.indexOf(type) == -1; + }); + this.initForNotSimpleType(); + + + this.$scope.validateJson = (json:string):boolean => { + if (!json) { + return true; + } + return this.ValidationUtils.validateJson(json); + }; + + + //scope methods + this.$scope.save = (doNotCloseModal?:boolean):void => { + let property:PropertyModel = this.$scope.editPropertyModel.property; + this.$scope.editPropertyModel.property.description = this.ValidationUtils.stripAndSanitize(this.$scope.editPropertyModel.property.description); + //if read only - or no changes made - just closes the modal + //need to check for property.value changes manually to detect if map properties deleted + if ((this.$scope.editPropertyModel.property.readonly && !this.$scope.isPropertyValueOwner) + || (!this.$scope.forms.editForm.$dirty && angular.equals(JSON.stringify(this.$scope.myValue), this.$scope.editPropertyModel.property.value))) { + this.$uibModalInstance.close(); + return; + } + + this.$scope.isLoading = true; + + let onPropertyFaild = (response):void => { + console.info('onFaild', response); + this.$scope.isLoading = false; + }; + + let onPropertySuccess = (propertyFromBE:PropertyModel):void => { + console.info('onPropertyResourceSuccess : ', propertyFromBE); + this.$scope.isLoading = false; + + if (!doNotCloseModal) { + this.$uibModalInstance.close(); + } else { + this.$scope.forms.editForm.$setPristine(); + this.$scope.editPropertyModel.property = new PropertyModel(); + } + }; + + //in case we have uniqueId we call update method + if (this.$scope.isPropertyValueOwner) { + if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { + let myValueString:string = JSON.stringify(this.$scope.myValue); + property.value = myValueString; + } + this.component.updateInstanceProperty(property).then(onPropertySuccess, onPropertyFaild); + } else { + if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) { + let myValueString:string = JSON.stringify(this.$scope.myValue); + property.defaultValue = myValueString; + } else { + this.$scope.editPropertyModel.property.defaultValue = this.$scope.editPropertyModel.property.value; + } + this.component.addOrUpdateProperty(property).then(onPropertySuccess, onPropertyFaild); + } + }; + + this.$scope.getPrev = ():void=> { + this.property = this.filteredProperties[--this.$scope.currentPropertyIndex]; + this.initResource(); + this.initForNotSimpleType(); + this.$scope.isLastProperty = false; + }; + + this.$scope.getNext = ():void=> { + this.property = this.filteredProperties[++this.$scope.currentPropertyIndex]; + this.initResource(); + this.initForNotSimpleType(); + this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1); + }; + + this.$scope.isSimpleType = (typeName:string):boolean=> { + return typeName && this.$scope.editPropertyModel.simpleTypes.indexOf(typeName) != -1; + }; + + this.$scope.showSchema = ():boolean => { + return [PROPERTY_TYPES.LIST, PROPERTY_TYPES.MAP].indexOf(this.$scope.editPropertyModel.property.type) > -1; + }; + + this.$scope.getValidationPattern = (type:string):RegExp => { + return this.ValidationUtils.getValidationPattern(type); + }; + + this.$scope.validateIntRange = (value:string):boolean => { + return !value || this.ValidationUtils.validateIntRange(value); + }; + + this.$scope.close = ():void => { + this.$uibModalInstance.close(); + }; + + // put default value when instance value is empty + this.$scope.onValueChange = ():void => { + if (!this.$scope.editPropertyModel.property.value) { + if (this.$scope.isPropertyValueOwner) { + this.$scope.editPropertyModel.property.value = this.$scope.editPropertyModel.property.defaultValue; + } + } + }; + + // Add the done button at the footer. + this.$scope.footerButtons = [ + {'name': 'Save', 'css': 'blue', 'callback': this.$scope.save}, + {'name': 'Cancel', 'css': 'grey', 'callback': this.$scope.close} + ]; + + this.$scope.$watch("forms.editForm.$invalid", (newVal, oldVal) => { + this.$scope.footerButtons[0].disabled = this.$scope.forms.editForm.$invalid; + }); + + this.$scope.getDefaultValue = ():any => { + return this.$scope.isPropertyValueOwner ? this.$scope.editPropertyModel.property.defaultValue : null; + }; + + this.$scope.onTypeChange = ():void => { + this.$scope.editPropertyModel.property.value = ''; + this.$scope.editPropertyModel.property.defaultValue = ''; + this.setMaxLength(); + this.initForNotSimpleType(); + }; + + this.$scope.onSchemaTypeChange = ():void => { + if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.MAP) { + this.$scope.myValue = {'': null}; + } else if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.LIST) { + this.$scope.myValue = []; + } + this.setMaxLength(); + }; + + this.$scope.delete = (property:PropertyModel):void => { + let onOk = ():void => { + this.component.deleteProperty(property.uniqueId).then( + this.$scope.close + ); + }; + let title:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TITLE"); + let message:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TEXT", "{'name': '" + property.name + "'}"); + this.ModalsHandler.openConfirmationModal(title, message, false).then(onOk); + }; + } +} diff --git a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html new file mode 100644 index 0000000000..f92d9a5ddc --- /dev/null +++ b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html @@ -0,0 +1,201 @@ +<sdc-modal modal="modalInstanceProperty" type="classic" class="sdc-edit-property-container" buttons="footerButtons" header="{{isNew ? 'Add' : 'Update' }} Property" show-close-button="true" data-tests-id="sdc-edit-property-container"> + <loader data-display="isLoading" relative="false" size="medium"></loader> + <div class="sdc-modal-top-bar" data-ng-if="!isNew"> + <div class="sdc-modal-top-bar-buttons"> + <span ng-click="delete(editPropertyModel.property)" data-ng-class="{'disabled' : isPropertyValueOwner || editPropertyModel.property.readonly}" class="sprite-new delete-btn" data-tests-id="delete_property" sdc-smart-tooltip="">Delete</span> + <span class="delimiter"></span> + <span data-ng-click="getPrev()" data-ng-class="{'disabled' : !currentPropertyIndex }" class="sprite-new left-arrow" data-tests-id="get-prev" sdc-smart-tooltip="">Previous</span> + <span data-ng-click="getNext()" data-ng-class="{'disabled' : isLastProperty }" class="sprite-new right-arrow" data-tests-id="get-next" sdc-smart-tooltip="">Next</span> + </div> + </div> + + <div class="sdc-edit-property-form-container" > + <perfect-scrollbar scroll-y-margin-offset="0" include-padding="true" class="scrollbar-container"> + <form novalidate class="w-sdc-form two-columns" name="forms.editForm" > + + <div class="w-sdc-form-columns-wrapper"> + + <div class="w-sdc-form-column"> + + <!-- Name --> + <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm.propertyName.$dirty && forms.editForm.propertyName.$invalid)}"> + <label class="i-sdc-form-label" ng-class="{'required': !isService}">Name</label> + <input class="i-sdc-form-input" + data-tests-id="propertyName" + data-ng-maxlength="50" + data-ng-disabled="!isNew || editPropertyModel.property.readonly" + maxlength="50" + data-ng-model="editPropertyModel.property.name" + type="text" + name="propertyName" + data-ng-pattern="propertyNameValidationPattern" + data-required + data-ng-model-options="{ debounce: 200 }" + autofocus /> + + <div class="input-error" data-ng-show="forms.editForm.propertyName.$dirty && forms.editForm.propertyName.$invalid"> + <span ng-show="forms.editForm.propertyName.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Property name' }"></span> + <span ng-show="forms.editForm.propertyName.$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '50' }"></span> + <span ng-show="forms.editForm.propertyName.$error.pattern" translate="VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED"></span> + </div> + </div> + </div> + + <div class="w-sdc-form-column"> + <div class="w-sdc-form-columns-wrapper"> + <div class="w-sdc-form-column"> + <!-- Type --> + <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm.type.$dirty && forms.editForm.type.$invalid)}"> + <label class="i-sdc-form-label" ng-class="{'required': !isService}">Type</label> + <select class="i-sdc-form-select" + data-tests-id="propertyType" + data-required + data-ng-disabled="isPropertyValueOwner || editPropertyModel.property.readonly" + name="type" + data-ng-change="onTypeChange()" + data-ng-model="editPropertyModel.property.type"> + <option value="">Choose Type</option> + <option data-ng-repeat="type in editPropertyModel.types" + value="{{type}}">{{type}}</option> + <option data-ng-repeat="type in nonPrimitiveTypes" + value="{{type}}">{{type.replace("org.openecomp.datatypes.heat.","")}}</option> + </select> + + <div class="input-error" data-ng-show="forms.editForm.type.$dirty && forms.editForm.type.$invalid"> + <span ng-show="forms.editForm.type.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Type' }"></span> + </div> + </div> + </div> + <div class="w-sdc-form-column" data-ng-if="showSchema()"> + <!-- Entry Schema --> + <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm.schemaType.$dirty && forms.editForm.schemaType.$invalid)}"> + <label class="i-sdc-form-label required">Entry Schema</label> + <select class="i-sdc-form-select" + data-required + data-tests-id="schema-type" + data-ng-disabled="isPropertyValueOwner || editPropertyModel.property.readonly" + name="schemaType" + data-ng-change="onSchemaTypeChange()" + data-ng-model="editPropertyModel.property.schema.property.type"> + <option value="">Choose Schema Type</option> + <option data-ng-repeat="type in editPropertyModel.simpleTypes" + value="{{type}}">{{type}}</option> + <option data-ng-repeat="type in nonPrimitiveTypes" + value="{{type}}">{{type.replace("org.openecomp.datatypes.heat.","")}}</option> + </select> + + <div class="input-error" data-ng-show="forms.editForm.schemaType.$dirty && forms.editForm.schemaType.$invalid"> + <span ng-show="forms.editForm.schemaType.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Entry schema' }"></span> + </div> + </div> + </div> + </div> + + <!-- Constraints by type --> + <div class="i-sdc-form-item" data-ng-if="false"> + <label class="i-sdc-form-label required">Constraints by type</label> + <div> + Should be constraints by type(TBD) + </div> + </div> + + </div> + + </div> + <!-- Description --> + <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm.description.$dirty && forms.editForm.description.$invalid)}"> + <label class="i-sdc-form-label">Description</label> + <textarea class="i-sdc-form-textarea" + data-ng-maxlength="400" + data-ng-disabled="isPropertyValueOwner || editPropertyModel.property.readonly" + maxlength="400" + data-ng-pattern="commentValidationPattern" + name="description" + data-ng-model="editPropertyModel.property.description" + data-ng-model-options="{ debounce: 200 }" + data-tests-id="description" + ></textarea> + + <div class="input-error" data-ng-show="forms.editForm.description.$dirty && forms.editForm.description.$invalid"> + <span ng-show="forms.editForm.description.$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '256' }"></span> + <span ng-show="forms.editForm.description.$error.pattern" translate="VALIDATION_ERROR_SPECIAL_CHARS_NOT_ALLOWED"></span> + <span ng-show="forms.editForm.description.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Description' }"></span> + </div> + </div> + <!-- Default value --> + + <div class="default-value-section i-sdc-form-item"> + <label class="i-sdc-form-label">Default Value</label> + <div data-ng-if="isTypeDataType"> + <fields-structure value-obj-ref="myValue" + type-name="editPropertyModel.property.type" + parent-form-obj="forms.editForm" + fields-prefix-name="currentPropertyIndex" + read-only="editPropertyModel.property.readonly && !isPropertyValueOwner" + default-value="{{getDefaultValue()}}" + expand-by-default="true"></fields-structure> + + </div> + <div data-ng-if="!isTypeDataType" ng-switch="editPropertyModel.property.type"> + <div ng-switch-when="map"> + <type-map value-obj-ref="myValue" + schema-property="editPropertyModel.property.schema.property" + parent-form-obj="forms.editForm" + fields-prefix-name="currentPropertyIndex" + read-only="editPropertyModel.property.readonly && !isPropertyValueOwner" + default-value="{{getDefaultValue()}}" + max-length="maxLength"></type-map> + </div> + <div ng-switch-when="list"> + <type-list value-obj-ref="myValue" + schema-property="editPropertyModel.property.schema.property" + parent-form-obj="forms.editForm" + fields-prefix-name="currentPropertyIndex" + read-only="editPropertyModel.property.readonly && !isPropertyValueOwner" + default-value="{{getDefaultValue()}}" + max-length="maxLength"></type-list> + </div> + <div ng-switch-default> + <div class="i-sdc-form-item" data-ng-class="{error:(forms.editForm.value.$dirty && forms.editForm.value.$invalid), 'input-group' : editPropertyModel.property.addOn}"> + <span ng-if="editPropertyModel.property.addOn" class="input-group-addon">{{editPropertyModel.property.addOn}}</span> + <input class="i-sdc-form-input" + data-tests-id="defaultvalue" + ng-if="!((editPropertyModel.property.simpleType||editPropertyModel.property.type) == 'boolean')" + data-ng-maxlength="maxLength" + data-ng-disabled="editPropertyModel.property.readonly && !isPropertyValueOwner" + maxlength="{{maxLength}}" + data-ng-model="editPropertyModel.property.value" + type="text" + name="value" + data-ng-pattern="getValidationPattern((editPropertyModel.property.simpleType||editPropertyModel.property.type))" + data-ng-model-options="{ debounce: 200 }" + data-ng-change="('json'==editPropertyModel.property.type && forms.editForm.value.$setValidity('pattern', validateJson(editPropertyModel.property.value))) + ||(!forms.editForm.value.$error.pattern && ('integer'==editPropertyModel.property.type && forms.editForm.value.$setValidity('pattern', validateIntRange(editPropertyModel.property.value)) || onValueChange()))" + data-ng-change="" + autofocus /> + <select class="i-sdc-form-select" + data-tests-id="booleantype" + ng-if="(editPropertyModel.property.simpleType||editPropertyModel.property.type) == 'boolean'" + data-ng-disabled="editPropertyModel.property.readonly && !isPropertyValueOwner" + name="value" + data-ng-change="onValueChange()" + data-ng-model="editPropertyModel.property.value"> + <option value="true">true</option> + <option value="false">false</option> + </select> + + <div class="input-error" data-ng-show="forms.editForm.value.$dirty && forms.editForm.value.$invalid"> + <span ng-show="forms.editForm.value.$error.required" translate="VALIDATION_ERROR_REQUIRED" translate-values="{'field': 'Property' }"></span> + <span ng-show="forms.editForm.value.$error.maxlength" translate="VALIDATION_ERROR_MAX_LENGTH" translate-values="{'max': '{{maxLength}}' }"></span> + <span ng-show="forms.editForm.value.$error.pattern" translate="PROPERTY_EDIT_PATTERN"></span> + </div> + </div> + </div> + </div> + </div> + <span class="w-sdc-form-note" data-ng-show="forms.editForm.$invalid && false" translate="LABEL_ALL_FIELDS_ARE_MANDATORY"></span> + </form> + </perfect-scrollbar> + </div> + +</sdc-modal> |