Provide capability to add user specified name for service role/function
[sdc.git] / catalog-ui / src / app / view-models / workspace / tabs / general / general-view-model.ts
index c319b80..a0e8ca9 100644 (file)
@@ -30,15 +30,18 @@ import {
     instantiationType,
     ModalsHandler,
     ResourceType,
-    ValidationUtils
+    ValidationUtils,
+    FileUtils,
+    ServiceCsarReader
 } from "app/utils";
 import {EventListenerService, ProgressService} from "app/services";
 import {CacheService, ElementService, ModelService, ImportVSPService, OnboardingService} from "app/services-ng2";
 import {Component, IAppConfigurtaion, ICsarComponent, IMainCategory, IMetadataKey, ISubCategory, IValidate, Resource, Service} from "app/models";
 import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
-import {CATEGORY_SERVICE_METADATA_KEYS, PREVIOUS_CSAR_COMPONENT} from "../../../../utils/constants";
+import {CATEGORY_SERVICE_METADATA_KEYS, PREVIOUS_CSAR_COMPONENT, DEFAULT_MODEL_NAME} from "../../../../utils/constants";
 import {Observable} from "rxjs";
 import {Model} from "../../../../models/model";
+import {SdcUiServices} from "onap-ui-angular/dist";
 
 export class Validation {
     componentNameValidationPattern:RegExp;
@@ -82,6 +85,10 @@ export interface IGeneralScope extends IWorkspaceViewModelScope {
     instantiationTypes:Array<instantiationType>;
     isHiddenCategorySelected: boolean;
     isModelRequired: boolean;
+    othersFlag: boolean;
+    functionOption: string;
+    othersRoleFlag: boolean;
+    roleOption: string;
 
     save():Promise<any>;
     revert():void;
@@ -93,9 +100,10 @@ export interface IGeneralScope extends IWorkspaceViewModelScope {
     convertCategoryStringToOneArray(category:string, subcategory:string):Array<IMainCategory>;
     onCategoryChange():void;
     onEcompGeneratedNamingChange():void;
+    onModelChange():void;
     onBaseTypeChange():void;
     openOnBoardingModal():void;
-    initCategoreis():void;
+    initCategories():void;
     initEnvironmentContext():void;
     initInstantiationTypes():void;
     initBaseTypes():void;
@@ -104,6 +112,8 @@ export interface IGeneralScope extends IWorkspaceViewModelScope {
     possibleToUpdateIcon():boolean;
     initModel():void;
     isVspImport(): boolean;
+    setServiceFunction(option:string):void;
+    setServiceRole(option:string):void;
 }
 
 // tslint:disable-next-line:max-classes-per-file
@@ -120,9 +130,11 @@ export class GeneralViewModel {
         'VendorModelNumberValidationPattern',
         'CommentValidationPattern',
         'ValidationUtils',
+        'FileUtils',
         'sdcConfig',
         '$state',
         'ModalsHandler',
+        'ModalServiceSdcUI',
         'EventListenerService',
         'Notification',
         'Sdc.Services.ProgressService',
@@ -147,9 +159,11 @@ export class GeneralViewModel {
                 private VendorModelNumberValidationPattern:RegExp,
                 private CommentValidationPattern:RegExp,
                 private ValidationUtils:ValidationUtils,
+                private FileUtils: FileUtils,
                 private sdcConfig:IAppConfigurtaion,
                 private $state:ng.ui.IStateService,
                 private ModalsHandler:ModalsHandler,
+                private modalServiceSdcUI: SdcUiServices.ModalService,
                 private EventListenerService:EventListenerService,
                 private Notification:any,
                 private progressService:ProgressService,
@@ -168,9 +182,6 @@ export class GeneralViewModel {
         this.initScope();
     }
 
-
-
-
     private initScopeValidation = ():void => {
         this.$scope.validation = new Validation();
         this.$scope.validation.componentNameValidationPattern = this.ComponentNameValidationPattern;
@@ -215,7 +226,9 @@ export class GeneralViewModel {
                 if(this.$stateParams.componentCsar && this.$scope.component.lifecycleState === 'NOT_CERTIFIED_CHECKIN' && !this.$scope.isCreateMode()) {
                     this.$scope.importedToscaBrowseFileText = this.$scope.originComponent.name + ' (' + (this.$scope.originComponent as Resource).csarVersion + ')';
                 } else {
-                    this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion];
+                    if (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID]) {
+                        this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion];
+                    }
                 }
             }
         }
@@ -246,13 +259,14 @@ export class GeneralViewModel {
         this.$scope.progressService = this.progressService;
         this.$scope.componentCategories = new componentCategories();
         this.$scope.componentCategories.selectedCategory = this.$scope.component.selectedCategory;
-
+        this.$scope.othersFlag = false;
+        this.$scope.othersRoleFlag = false;
 
         // Init UIModel
         this.$scope.component.tags = _.without(this.$scope.component.tags, this.$scope.component.name);
 
         // Init categories
-        this.$scope.initCategoreis();
+        this.$scope.initCategories();
 
         // Init Environment Context
         this.$scope.initEnvironmentContext();
@@ -271,13 +285,45 @@ export class GeneralViewModel {
             if (resource.resourceType === ResourceType.VF && !resource.csarUUID) {
                 this.$scope.isShowFileBrowse = true;
             }
-        } else if(this.$scope.component.isService()){
+        } else if (this.$scope.component.isService()) {
             let service: Service = <Service>this.$scope.component;
             console.log(service.name + ": " + service.csarUUID);
-            if (service.importedFile) { // Component has imported file.
+            if (service.importedFile) {
                 this.$scope.isShowFileBrowse = true;
-                (<Service>this.$scope.component).serviceType = 'Service';
+                (<Service>this.$scope.component).ecompGeneratedNaming = true;
+                let blob = this.FileUtils.base64toBlob(service.importedFile.base64, "zip");
+                new ServiceCsarReader().read(blob).then(
+                    (serviceCsar) => {
+                        serviceCsar.serviceMetadata.contactId = this.cacheService.get("user").userId;
+                        (<Service>this.$scope.component).setComponentMetadata(serviceCsar.serviceMetadata);
+                        (<Service>this.$scope.component).model = serviceCsar.serviceMetadata.model;
+                        this.$scope.onModelChange();
+                        this.$scope.componentCategories.selectedCategory = serviceCsar.serviceMetadata.selectedCategory;
+                        this.$scope.onCategoryChange();
+                        serviceCsar.extraServiceMetadata.forEach((value: string, key: string) => {
+                            if (this.getMetadataKey(key)) {
+                                (<Service>this.$scope.component).categorySpecificMetadata[key] = value;
+                            }
+                        });
+                        (<Service>this.$scope.component).derivedFromGenericType = serviceCsar.substitutionNodeType;
+                        this.$scope.onBaseTypeChange();
+                        this.setFunctionRole(service);
+                    },
+                    (error) => {
+                        const errorMsg = this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT');
+                        console.error(errorMsg, error);
+                        const errorDetails = {
+                            'Error': this.capitalize(error.reason),
+                            'Details': this.capitalize(error.message)
+                        };
+                        this.modalServiceSdcUI.openErrorDetailModal('Error', this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT'),
+                            'error-modal', errorDetails);
+                        this.$state.go('dashboard');
+                    });
             }
+
+            this.setFunctionRole(service);
+
             if (this.$scope.isEditMode() && service.serviceType == 'Service' && !service.csarUUID) {
                 this.$scope.isShowFileBrowse = true;
             }
@@ -298,14 +344,13 @@ export class GeneralViewModel {
 
         if (this.$scope.component.isResource() &&
             (this.$scope.component as Resource).resourceType === ResourceType.VF ||
-                (this.$scope.component as Resource).resourceType === ResourceType.PNF && (this.$scope.component as Resource).csarUUID) {
+            (this.$scope.component as Resource).resourceType === ResourceType.PNF && (this.$scope.component as Resource).csarUUID) {
             this.$scope.isShowOnboardingSelectionBrowse = true;
             this.setImportedFileText();
         } else {
             this.$scope.isShowOnboardingSelectionBrowse = false;
         }
 
-
         //init file extensions based on the file that was imported.
         if (this.$scope.component.isResource() && (<Resource>this.$scope.component).importedFile) {
             let fileName:string = (<Resource>this.$scope.component).importedFile.filename;
@@ -323,8 +368,6 @@ export class GeneralViewModel {
             //(<Resource>this.$scope.component).importedFile.filetype="csar";
         }
 
-
-
         this.$scope.setValidState(true);
 
         this.$scope.calculateUnique = (mainCategory:string, subCategory:string):string => {
@@ -341,7 +384,6 @@ export class GeneralViewModel {
             this.$scope.originComponent.contactId = this.$scope.component.contactId;
         }
 
-
         this.$scope.$on('$destroy', () => {
             this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE);
             this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
@@ -349,6 +391,32 @@ export class GeneralViewModel {
 
     };
 
+    private capitalize(s) {
+        return s && s[0].toUpperCase() + s.slice(1);
+    }
+
+    private setFunctionRole = (service : Service) : void => {
+        if (service.serviceFunction) {
+            const functionList : string[] = this.$scope.getMetadataKeyValidValues('Service Function');
+            if (functionList.find(value => value == service.serviceFunction) != undefined) {
+                this.$scope.functionOption = service.serviceFunction;
+            } else {
+                this.$scope.functionOption = 'Others';
+                this.$scope.othersFlag = true;
+            }
+        }
+
+        if (service.serviceRole) {
+            const roleList : string[] = this.$scope.getMetadataKeyValidValues('Service Role');
+            if (roleList.find(value => value == service.serviceRole) != undefined) {
+                this.$scope.roleOption = service.serviceRole;
+            } else {
+                this.$scope.roleOption = 'Others';
+                this.$scope.othersRoleFlag = true;
+            }
+        }
+    }
+
     // Convert category string MainCategory_#_SubCategory to Array with one item (like the server except)
     private convertCategoryStringToOneArray = ():IMainCategory[] => {
         let tmp = this.$scope.component.selectedCategory.split("_#_");
@@ -413,11 +481,11 @@ export class GeneralViewModel {
         });
 
         return tempCategories;
-    };    
-   
+    };
+
     private initScopeMethods = ():void => {
 
-        this.$scope.initCategoreis = ():void => {
+        this.$scope.initCategories = ():void => {
             if (this.$scope.componentType === ComponentType.RESOURCE) {
                 this.$scope.categories = this.cacheService.get('resourceCategories');
 
@@ -431,7 +499,7 @@ export class GeneralViewModel {
                     //Flag to disbale category if service is created through External API
                     this.$scope.isHiddenCategorySelected = this.isHiddenCategory(this.$scope.component.selectedCategory);
                 }
-                
+
             }
         };
 
@@ -453,51 +521,74 @@ export class GeneralViewModel {
 
         this.$scope.initBaseTypes = ():void => {
             if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.component.categories) {
-                    let modelName = this.$scope.component.model ? this.$scope.component.model : null;
-                 this.elementService.getCategoryBasetypes(this.$scope.component.categories[0].name, modelName).subscribe((data: BaseTypeResponse[]) => {
-                        this.$scope.baseTypes = []
-                     this.$scope.baseTypeVersions = []
-                     data.forEach(baseType => {
-                            this.$scope.baseTypes.push(baseType.toscaResourceName)
-                         if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType){
-                                baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
-                     }});
-                 })
+                if (!this.$scope.component.derivedFromGenericType) {
+                    this.$scope.component.derivedFromGenericVersion = undefined;
+                    this.$scope.showBaseTypeVersions = false;
+                    return;
+                }
+                let modelName = this.$scope.component.model ? this.$scope.component.model : null;
+                const categoryName = this.$scope.component.categories[0].name;
+                this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((data: ListBaseTypesResponse) => {
+                    this.$scope.baseTypes = []
+                    this.$scope.baseTypeVersions = []
+                    this.$scope.isBaseTypeRequired = data.required;
+                    data.baseTypes.forEach(baseType => {
+                        this.$scope.baseTypes.push(baseType.toscaResourceName);
+                        if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) {
+                            baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
+                        }
+                    });
+                    this.$scope.showBaseTypeVersions = true;
+                })
             }
         };
 
         this.$scope.initModel = ():void => {
             this.$scope.isModelRequired = false;
-            this.$scope.models = [{id: '', name: 'SDC AID'}];
+            this.$scope.models = [];
+            this.$scope.defaultModelOption = DEFAULT_MODEL_NAME;
+            this.$scope.showDefaultModelOption = true;
+            if (this.$scope.componentType === ComponentType.SERVICE) {
+                this.filterCategoriesByModel(this.$scope.component.model);
+            }
             if (this.$scope.isCreateMode() && this.$scope.isVspImport()) {
                 if (this.$scope.component.componentMetadata.models) {
                     this.$scope.isModelRequired = true;
-                    const modelOptions = this.$scope.component.componentMetadata.models.map(value => {
-                        return {id: value, name: value};
-                    });
+                    const modelOptions = this.$scope.component.componentMetadata.models;
                     if (modelOptions.length == 1) {
                         this.$scope.models = modelOptions;
-                        this.$scope.component.model = modelOptions[0].id;
+                        this.$scope.component.model = modelOptions[0];
+                        this.$scope.showDefaultModelOption = false;
                     } else {
-                        this.$scope.models = [{id: '', name: 'Select'}, ...modelOptions];
+                        this.$scope.models = modelOptions.sort();
+                        this.$scope.defaultModelOption = 'Select';
                     }
                 }
                 return;
             }
 
-            this.modelService.getModels().subscribe((modelsFound: Model[]) => {
-                modelsFound.forEach(model => {this.$scope.models.push({id: model.name, name: model.name})});
-            });
-
-            this.$scope.models.sort(function (model1, model2) {
-                if (model1.id > model2.id) {
-                    return 1;
-                }
-                if (model1.id < model2.id) {
-                    return -1;
-                }
-                return 0;
-            });
+            if (!this.$scope.isCreateMode() && this.$scope.isVspImport()) {
+                this.modelService.getModels().subscribe((modelsFound: Model[]) => {
+                    modelsFound.sort().forEach(model => {
+                        if (this.$scope.component.model != undefined) {
+                            if (model.modelType == "NORMATIVE_EXTENSION") {
+                                if (this.$scope.component.model === model.name) {
+                                    this.$scope.component.model = model.derivedFrom;
+                                }
+                                this.$scope.models.push(model.derivedFrom)
+                            } else {
+                                this.$scope.models.push(model.name)
+                            }
+                        }
+                    });
+                });
+            } else {
+                this.modelService.getModelsOfType("normative").subscribe((modelsFound: Model[]) => {
+                    modelsFound.sort().forEach(model => {
+                        this.$scope.models.push(model.name)
+                    });
+                });
+            }
         };
 
         this.$scope.isVspImport = (): boolean => {
@@ -534,16 +625,16 @@ export class GeneralViewModel {
             this.importVSPService.openOnboardingModal(csarUUID, csarVersion).subscribe((result) => {
                 this.ComponentFactory.getComponentWithMetadataFromServer(result.type.toUpperCase(), result.previousComponent.uniqueId).then(
                     (component:Component)=> {
-                    if (result.componentCsar && component.isResource()){
-                        this.cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component));
-                        component = this.ComponentFactory.updateComponentFromCsar(result.componentCsar, <Resource>component);
-                    }
-                    this.$scope.setComponent(component);
-                    this.$scope.save();
-                    this.setImportedFileText();
-                }, ()=> {
-                    // ERROR
-                });
+                        if (result.componentCsar && component.isResource()){
+                            this.cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component));
+                            component = this.ComponentFactory.updateComponentFromCsar(result.componentCsar, <Resource>component);
+                        }
+                        this.$scope.setComponent(component);
+                        this.$scope.save();
+                        this.setImportedFileText();
+                    }, ()=> {
+                        // ERROR
+                    });
             })
         };
 
@@ -582,7 +673,7 @@ export class GeneralViewModel {
 
                 return;
             }
-           
+
             let subtype:string = ComponentType.RESOURCE == this.$scope.componentType ? this.$scope.component.getComponentSubType() : undefined;
             if (subtype == "SRVC") {
                 subtype = "VF"
@@ -596,8 +687,9 @@ export class GeneralViewModel {
             const onSuccess = (validation:IValidate) => {
                 this.$scope.editForm['componentName'].$setValidity('nameExist', validation.isValid);
                 if (validation.isValid) {
-                    // update breadcrumb after changing name
-                    this.updateComponentNameInBreadcrumbs();
+                    this.updateComponentNameInBreadcrumbs(); // update breadcrumb after changing name
+                } else {
+                    this.$scope.editForm['componentName'].$setDirty();
                 }
             };
 
@@ -628,7 +720,6 @@ export class GeneralViewModel {
             }
         };
 
-
         this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, (nextState) => {
             if (this.$state.current.data.unsavedChanges && this.$scope.isValidForm) {
                 this.$scope.save().then(() => {
@@ -703,43 +794,54 @@ export class GeneralViewModel {
         });
 
         this.$scope.onCategoryChange = (): void => {
+            if (!this.$scope.component.selectedCategory) {
+                this.$scope.editForm['category'].$setDirty();
+            }
+            if (!this.$scope.component.description) {
+                this.$scope.editForm['description'].$setDirty();
+            }
             this.$scope.component.selectedCategory = this.$scope.componentCategories.selectedCategory;
-            this.$scope.component.categories = this.convertCategoryStringToOneArray();
-            this.$scope.component.icon = DEFAULT_ICON;
-            if (this.$scope.component.categories[0].metadataKeys) {
-                for (let metadataKey of this.$scope.component.categories[0].metadataKeys) {
-                    if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
-                        this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
-                   }
+            if (this.$scope.component.selectedCategory) {
+                this.$scope.component.categories = this.convertCategoryStringToOneArray();
+                this.$scope.component.icon = DEFAULT_ICON;
+                if (this.$scope.component.categories[0].metadataKeys) {
+                    for (let metadataKey of this.$scope.component.categories[0].metadataKeys) {
+                        if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
+                            this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
+                        }
+                        if (metadataKey.name === 'Service Role') {
+                            this.$scope.roleOption = this.$scope.component.categorySpecificMetadata[metadataKey.name];
+                        }
+                        if (metadataKey.name === 'Service Function') {
+                            this.$scope.functionOption = this.$scope.component.categorySpecificMetadata[metadataKey.name];
+                        }
+                    }
                 }
-            }
-            if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) {
-                for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) {
-                    if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
-                        this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
-                   }
+                if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) {
+                    for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) {
+                        if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
+                            this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
+                        }
+                    }
+                }
+                if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component.categories[0]) {
+                    const modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
+                    this.elementService.getCategoryBaseTypes(this.$scope.component.categories[0].name, modelName)
+                    .subscribe((data: ListBaseTypesResponse) => {
+                        if (this.$scope.isCreateMode()) {
+                            this.loadBaseTypes(data);
+                        } else {
+                            let isValidForBaseType:boolean = data.baseTypes.some(baseType => {
+                                return !this.$scope.component.derivedFromGenericType ||
+                                    baseType.toscaResourceName === this.$scope.component.derivedFromGenericType;
+                            });
+                            this.$scope.editForm['category'].$setValidity('validForBaseType', isValidForBaseType);
+                        }
+                    });
                 }
+            } else {
+                this.clearBaseTypes();
             }
-            if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component.categories[0]) {
-                   let modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
-                   this.elementService.getCategoryBasetypes(this.$scope.component.categories[0].name, modelName).subscribe((data: BaseTypeResponse[]) => {
-               
-                    if(this.$scope.isCreateMode()){
-                        this.$scope.baseTypes = []
-                        this.$scope.baseTypeVersions = []
-                        data.forEach(baseType => this.$scope.baseTypes.push(baseType.toscaResourceName));
-                        data[0].versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
-                        this.$scope.component.derivedFromGenericType = data[0].toscaResourceName;
-                        this.$scope.component.derivedFromGenericVersion = data[0].versions[0];
-                    } else {
-                        var isValidForBaseType:boolean = false;
-                        data.forEach(baseType => {if (!this.$scope.component.derivedFromGenericType || baseType.toscaResourceName === this.$scope.component.derivedFromGenericType){
-                            isValidForBaseType = true;
-                        };});
-                        this.$scope.editForm['category'].$setValidity('validForBaseType', isValidForBaseType);
-                    }
-                });
-            }   
         };
 
         this.$scope.onEcompGeneratedNamingChange = (): void => {
@@ -748,30 +850,39 @@ export class GeneralViewModel {
             }
         };
 
+        this.$scope.getCategoryDisplayNameOrName = (mainCategory: any): string => {
+            return mainCategory.displayName ? mainCategory.displayName : mainCategory.name ;
+        }
+
         this.$scope.onBaseTypeChange = (): void => {
-               let modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
-            this.elementService.getCategoryBasetypes(this.$scope.component.categories[0].name, modelName).subscribe((data: BaseTypeResponse[]) => {
-                     this.$scope.baseTypeVersions = []
-                     data.forEach(baseType => {
-                            if(baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) {
-                                    baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
-                             this.$scope.component.derivedFromGenericVersion = baseType.versions[0];
-                            };
-                     });
-             })
+            if (!this.$scope.component.derivedFromGenericType) {
+                this.$scope.component.derivedFromGenericVersion = undefined;
+                this.$scope.showBaseTypeVersions = false;
+                return;
+            }
+
+            const modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
+            const categoryName = this.$scope.component.categories[0].name;
+            this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((baseTypeResponseList: ListBaseTypesResponse) => {
+                this.$scope.baseTypeVersions = []
+                baseTypeResponseList.baseTypes.forEach(baseType => {
+                    if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) {
+                        baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
+                        this.$scope.component.derivedFromGenericVersion = baseType.versions[0];
+                    }
+                });
+                this.$scope.showBaseTypeVersions = true;
+            });
         };
 
         this.$scope.onModelChange = (): void => {
-            if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.component.categories) {
+            if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.categories) {
                 let modelName = this.$scope.component.model ? this.$scope.component.model : null;
-                this.elementService.getCategoryBasetypes(this.$scope.component.categories[0].name, modelName).subscribe((data: BaseTypeResponse[]) => {
-                    this.$scope.baseTypes = []
-                    this.$scope.baseTypeVersions = []
-                    data.forEach(baseType => this.$scope.baseTypes.push(baseType.toscaResourceName));
-                    data[0].versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
-                    this.$scope.component.derivedFromGenericType = data[0].toscaResourceName;
-                    this.$scope.component.derivedFromGenericVersion = data[0].versions[0];
-                });
+                this.$scope.component.categories = undefined;
+                this.$scope.component.selectedCategory = undefined;
+                this.$scope.componentCategories.selectedCategory = undefined;
+                this.filterCategoriesByModel(modelName);
+                this.filterBaseTypesByModelAndCategory(modelName)
             }
         };
 
@@ -780,24 +891,58 @@ export class GeneralViewModel {
                 this.$scope.component.icon = DEFAULT_ICON;
             }
         };
-        this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload);
 
+        this.$scope.setServiceFunction = (option:string): void => {
+            if (option === 'Others') {
+                this.$scope.othersFlag = true;
+                (<Service>this.$scope.component).serviceFunction = '';
+            } else {
+                this.$scope.othersFlag = false;
+                (<Service>this.$scope.component).serviceFunction = option;
+            }
+
+        }
+
+        this.$scope.setServiceRole = (option:string): void => {
+            if (option === 'Others') {
+                this.$scope.othersRoleFlag = true;
+                (<Service>this.$scope.component).serviceRole = '';
+            } else {
+                this.$scope.othersRoleFlag = false;
+                (<Service>this.$scope.component).serviceRole = option;
+            }
+
+        }
+
+        this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload);
 
         this.$scope.isMetadataKeyMandatory = (key: string): boolean => {
-            let metadataKey = this.getMetadataKey(this.$scope.component.categories, key);
+            let metadataKey = this.getMetadataKey(key);
             return metadataKey && metadataKey.mandatory;
         }
 
         this.$scope.getMetadataKeyValidValues = (key: string): string[] => {
-            let metadataKey = this.getMetadataKey(this.$scope.component.categories, key);
+            let metadataKey = this.getMetadataKey(key);
+            if (metadataKey) {
+                if (key == 'Service Function' || key == 'Service Role') {
+                    return metadataKey.validValues.concat("Others");
+                } else {
+                    return metadataKey.validValues;
+                }
+            }
+            return [];
+        }
+
+        this.$scope.getMetadataDisplayName = (key: string): string => {
+            let metadataKey = this.getMetadataKey(key);
             if (metadataKey) {
-                return metadataKey.validValues;
+                return metadataKey.displayName ? metadataKey.displayName : metadataKey.name;
             }
-            return []; 
+            return "";
         }
 
         this.$scope.isMetadataKeyForComponentCategory = (key: string): boolean => {
-            return this.getMetadataKey(this.$scope.component.categories, key) != null;
+            return this.getMetadataKey(key) != null;
         }
 
         this.$scope.isCategoryServiceMetadataKey = (key: string): boolean => {
@@ -805,35 +950,102 @@ export class GeneralViewModel {
         }
 
         this.$scope.isMetadataKeyForComponentCategoryService = (key: string, attribute: string): boolean => {
-            let metadatakey = this.getMetadataKey(this.$scope.component.categories, key);
+            let metadatakey = this.getMetadataKey(key);
             if (metadatakey && (!this.$scope.component[attribute] || !metadatakey.validValues.find(v => v === this.$scope.component[attribute]))) {
                 this.$scope.component[attribute] = metadatakey.defaultValue;
             }
             return metadatakey != null;
-         }
+        }
+
+        this.$scope.isNotApplicableMetadataKeys = (key: string): boolean => {
+            return this.$scope.component.categories && this.$scope.component.categories[0].notApplicableMetadataKeys && this.$scope.component.categories[0].notApplicableMetadataKeys.some(item => item === key);
+        }
+    }
+
+    private filterCategoriesByModel(modelName:string) {
+        // reload categories
+        this.$scope.initCategories();
+        this.$scope.categories = this.$scope.categories.filter(category =>
+            !modelName ? !category.models || category.models.indexOf(DEFAULT_MODEL_NAME) !== -1 : category.models !== null && category.models.indexOf(modelName) !== -1);
+    }
+
+    private filterBaseTypesByModelAndCategory(modelName:string) {
+        let categories = this.$scope.component.categories;
+        if (categories) {
+            this.elementService.getCategoryBaseTypes(categories[0].name, modelName).subscribe((data: ListBaseTypesResponse) => {
+                this.loadBaseTypes(data);
+            });
+            return;
+        }
+        this.clearBaseTypes();
+    }
+
+    private loadBaseTypes(baseTypeResponseList: ListBaseTypesResponse) {
+        this.$scope.isBaseTypeRequired = baseTypeResponseList.required;
+        this.$scope.baseTypes = [];
+        this.$scope.baseTypeVersions = [];
+        let defaultBaseType = baseTypeResponseList.defaultBaseType;
+        baseTypeResponseList.baseTypes.forEach(baseType => this.$scope.baseTypes.push(baseType.toscaResourceName));
+        if (this.$scope.isBaseTypeRequired || defaultBaseType != null) {
+            let baseType = baseTypeResponseList.baseTypes[0];
+            if(defaultBaseType != null){
+                baseTypeResponseList.baseTypes.forEach(baseTypeObj => {
+                    if(baseTypeObj.toscaResourceName == defaultBaseType) {
+                        baseType = baseTypeObj;
+                    }
+                });
+            }
+            if((<Service>this.$scope.component).derivedFromGenericType) {
+                baseTypeResponseList.baseTypes.forEach(baseTypeObj => {
+                    if(baseTypeObj.toscaResourceName == (<Service>this.$scope.component).derivedFromGenericType) {
+                        baseType = baseTypeObj;
+                    }
+                });
+            }
+            baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
+            this.$scope.component.derivedFromGenericType = baseType.toscaResourceName;
+            this.$scope.component.derivedFromGenericVersion = this.$scope.baseTypeVersions[0];
+            this.$scope.showBaseTypeVersions = true;
+            return
+        }
+        this.$scope.component.derivedFromGenericType = undefined;
+        this.$scope.component.derivedFromGenericVersion = undefined;
+        this.$scope.showBaseTypeVersions = false;
+    }
+
+    private clearBaseTypes() {
+        this.$scope.isBaseTypeRequired = false;
+        this.$scope.baseTypes = [];
+        this.$scope.baseTypeVersions = [];
+        this.$scope.component.derivedFromGenericType = undefined;
+        this.$scope.component.derivedFromGenericVersion = undefined;
+        this.$scope.showBaseTypeVersions = false;
     }
 
     private setUnsavedChanges = (hasChanges: boolean): void => {
         this.$state.current.data.unsavedChanges = hasChanges;
     }
 
-    private getMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
-        let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key);
-        if (!metadataKey){
-            return this.getCategoryMetadataKey(this.$scope.component.categories, key);
+    private getMetadataKey(key: string) : IMetadataKey {
+        if (this.$scope.component.categories) {
+            let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key);
+            if (!metadataKey){
+                return this.getCategoryMetadataKey(this.$scope.component.categories, key);
+            }
+            return metadataKey;
         }
-        return metadataKey;
+        return null;
     }
 
     private getSubcategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
-           if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+        if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
             return categories[0].subcategories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
         }
         return null;
     }
 
     private getCategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
-           if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+        if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
             return categories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
         }
         return null;
@@ -844,4 +1056,3 @@ export class GeneralViewModel {
     }
 
 }
-