service role and service function metadata not imported
[sdc.git] / catalog-ui / src / app / view-models / workspace / tabs / general / general-view-model.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 'use strict';
22 import * as _ from "lodash";
23 import {Dictionary} from "lodash";
24 import {
25     ComponentFactory,
26     ComponentState,
27     ComponentType,
28     DEFAULT_ICON,
29     EVENTS,
30     instantiationType,
31     ModalsHandler,
32     ResourceType,
33     ValidationUtils,
34     FileUtils,
35     ServiceCsarReader
36 } from "app/utils";
37 import {EventListenerService, ProgressService} from "app/services";
38 import {CacheService, ElementService, ModelService, ImportVSPService, OnboardingService} from "app/services-ng2";
39 import {Component, IAppConfigurtaion, ICsarComponent, IMainCategory, IMetadataKey, ISubCategory, IValidate, Resource, Service} from "app/models";
40 import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
41 import {CATEGORY_SERVICE_METADATA_KEYS, PREVIOUS_CSAR_COMPONENT, DEFAULT_MODEL_NAME} from "../../../../utils/constants";
42 import {Observable} from "rxjs";
43 import {Model} from "../../../../models/model";
44 import {SdcUiServices} from "onap-ui-angular/dist";
45
46 export class Validation {
47     componentNameValidationPattern:RegExp;
48     contactIdValidationPattern:RegExp;
49     tagValidationPattern:RegExp;
50     VendorReleaseValidationPattern:RegExp;
51     VendorNameValidationPattern:RegExp;
52     VendorModelNumberValidationPattern:RegExp;
53     commentValidationPattern:RegExp;
54 }
55
56 export class componentCategories {//categories field bind to this obj in order to solve this bug: DE242059
57     selectedCategory:string;
58 }
59
60 export class componentModel {
61     selectedModel:string;
62 }
63
64 export interface IEnvironmentContext {
65     defaultValue:string;
66     validValues:Array<string>;
67 }
68
69 export interface IGeneralScope extends IWorkspaceViewModelScope {
70     validation:Validation;
71     editForm:ng.IFormController;
72     categories:Array<IMainCategory>;
73     environmentContextObj:IEnvironmentContext;
74     latestCategoryId:string;
75     latestVendorName:string;
76     importedFileExtension:any;
77     isCreate:boolean;
78     isShowFileBrowse:boolean;
79     isShowOnboardingSelectionBrowse:boolean;
80     importedToscaBrowseFileText:string;
81     importCsarProProgressKey:string;
82     browseFileLabel:string;
83     componentCategories:componentCategories;
84     componentModel:componentModel;
85     instantiationTypes:Array<instantiationType>;
86     isHiddenCategorySelected: boolean;
87     isModelRequired: boolean;
88     othersFlag: boolean;
89     functionOption: string;
90     othersRoleFlag: boolean;
91     roleOption: string;
92
93     save():Promise<any>;
94     revert():void;
95     onImportFileChange():void;
96     validateField(field:any):boolean;
97     validateName(isInit:boolean):void;
98     calculateUnique(mainCategory:string, subCategory:string):string; // Build unique string from main and sub category
99     onVendorNameChange(oldVendorName:string):void;
100     convertCategoryStringToOneArray(category:string, subcategory:string):Array<IMainCategory>;
101     onCategoryChange():void;
102     onEcompGeneratedNamingChange():void;
103     onModelChange():void;
104     onBaseTypeChange():void;
105     openOnBoardingModal():void;
106     initCategories():void;
107     initEnvironmentContext():void;
108     initInstantiationTypes():void;
109     initBaseTypes():void;
110     onInstantiationTypeChange():void;
111     updateIcon():void;
112     possibleToUpdateIcon():boolean;
113     initModel():void;
114     isVspImport(): boolean;
115     setServiceFunction(option:string):void;
116     setServiceRole(option:string):void;
117 }
118
119 // tslint:disable-next-line:max-classes-per-file
120 export class GeneralViewModel {
121
122     static '$inject' = [
123         '$scope',
124         'Sdc.Services.CacheService',
125         'ComponentNameValidationPattern',
126         'ContactIdValidationPattern',
127         'TagValidationPattern',
128         'VendorReleaseValidationPattern',
129         'VendorNameValidationPattern',
130         'VendorModelNumberValidationPattern',
131         'CommentValidationPattern',
132         'ValidationUtils',
133         'FileUtils',
134         'sdcConfig',
135         '$state',
136         'ModalsHandler',
137         'ModalServiceSdcUI',
138         'EventListenerService',
139         'Notification',
140         'Sdc.Services.ProgressService',
141         '$interval',
142         '$filter',
143         '$timeout',
144         'OnboardingService',
145         'ComponentFactory',
146         'ImportVSPService',
147         'ElementService',
148         'ModelService',
149         '$stateParams'
150     ];
151
152     constructor(private $scope:IGeneralScope,
153                 private cacheService:CacheService,
154                 private ComponentNameValidationPattern:RegExp,
155                 private ContactIdValidationPattern:RegExp,
156                 private TagValidationPattern:RegExp,
157                 private VendorReleaseValidationPattern:RegExp,
158                 private VendorNameValidationPattern:RegExp,
159                 private VendorModelNumberValidationPattern:RegExp,
160                 private CommentValidationPattern:RegExp,
161                 private ValidationUtils:ValidationUtils,
162                 private FileUtils: FileUtils,
163                 private sdcConfig:IAppConfigurtaion,
164                 private $state:ng.ui.IStateService,
165                 private ModalsHandler:ModalsHandler,
166                 private modalServiceSdcUI: SdcUiServices.ModalService,
167                 private EventListenerService:EventListenerService,
168                 private Notification:any,
169                 private progressService:ProgressService,
170                 protected $interval:any,
171                 private $filter:ng.IFilterService,
172                 private $timeout:ng.ITimeoutService,
173                 private onBoardingService: OnboardingService,
174                 private ComponentFactory:ComponentFactory,
175                 private importVSPService: ImportVSPService,
176                 private elementService: ElementService,
177                 private modelService: ModelService,
178                 private $stateParams: any) {
179
180         this.initScopeValidation();
181         this.initScopeMethods();
182         this.initScope();
183     }
184
185     private initScopeValidation = ():void => {
186         this.$scope.validation = new Validation();
187         this.$scope.validation.componentNameValidationPattern = this.ComponentNameValidationPattern;
188         this.$scope.validation.contactIdValidationPattern = this.ContactIdValidationPattern;
189         this.$scope.validation.tagValidationPattern = this.TagValidationPattern;
190         this.$scope.validation.VendorReleaseValidationPattern = this.VendorReleaseValidationPattern;
191         this.$scope.validation.VendorNameValidationPattern = this.VendorNameValidationPattern;
192         this.$scope.validation.VendorModelNumberValidationPattern = this.VendorModelNumberValidationPattern;
193         this.$scope.validation.commentValidationPattern = this.CommentValidationPattern;
194     };
195
196     private loadOnboardingFileCache = (): Observable<Dictionary<Dictionary<string>>> => {
197         let onboardCsarFilesMap:Dictionary<Dictionary<string>>;
198         let onSuccess = (vsps:Array<ICsarComponent>) => {
199             onboardCsarFilesMap = {};
200             _.each(vsps, (vsp:ICsarComponent)=>{
201                 onboardCsarFilesMap[vsp.packageId] = onboardCsarFilesMap[vsp.packageId] || {};
202                 onboardCsarFilesMap[vsp.packageId][vsp.version] = vsp.vspName + " (" + vsp.version + ")";
203             });
204             this.cacheService.set('onboardCsarFilesMap', onboardCsarFilesMap);
205             return onboardCsarFilesMap;
206         };
207         let onError = (): void =>{
208             console.log("Error getting onboarding list");
209         };
210         return this.onBoardingService.getOnboardingVSPs().map(onSuccess, onError);
211     };
212
213     private setImportedFileText = ():void => {
214
215         if(!this.$scope.isShowOnboardingSelectionBrowse) return;
216
217         //these variables makes it easier to read this logic
218         let csarUUID:string = (<Resource>this.$scope.component).csarUUID;
219         let csarVersion:string = (<Resource>this.$scope.component).csarVersion;
220
221         let onboardCsarFilesMap:Dictionary<Dictionary<string>> = this.cacheService.get('onboardCsarFilesMap');
222         let assignFileName = ():void => {
223             if(this.$scope.component.vspArchived){
224                 this.$scope.importedToscaBrowseFileText = 'VSP is archived';
225             } else {
226                 if(this.$stateParams.componentCsar && this.$scope.component.lifecycleState === 'NOT_CERTIFIED_CHECKIN' && !this.$scope.isCreateMode()) {
227                     this.$scope.importedToscaBrowseFileText = this.$scope.originComponent.name + ' (' + (this.$scope.originComponent as Resource).csarVersion + ')';
228                 } else {
229                     if (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID]) {
230                         this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion];
231                     }
232                 }
233             }
234         }
235
236
237         if(this.$scope.component.vspArchived || (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID] && onboardCsarFilesMap[csarUUID][csarVersion])){ //check that the file name is already in cache
238             assignFileName();
239         } else {
240             this.loadOnboardingFileCache().subscribe((onboardingFiles) => {
241                 onboardCsarFilesMap = onboardingFiles;
242                 this.cacheService.set('onboardCsarFilesMap', onboardingFiles);
243                 assignFileName();
244             }, ()=> {});
245         }
246
247     }
248
249     isCreateModeAvailable(verifyObj:string): boolean {
250         var isCheckout:boolean = ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState;
251         return this.$scope.isCreateMode() || (isCheckout && !verifyObj)
252     }
253
254     private initScope = ():void => {
255
256         this.$scope.importCsarProgressKey = "importCsarProgressKey";
257
258         this.$scope.browseFileLabel = (this.$scope.component.isResource() && ((<Resource>this.$scope.component).resourceType === ResourceType.VF || (<Resource>this.$scope.component).resourceType === 'SRVC')) ||  this.$scope.component.isService() ? 'Upload File:' : 'Upload VFC:';
259         this.$scope.progressService = this.progressService;
260         this.$scope.componentCategories = new componentCategories();
261         this.$scope.componentCategories.selectedCategory = this.$scope.component.selectedCategory;
262         this.$scope.othersFlag = false;
263         this.$scope.othersRoleFlag = false;
264
265         // Init UIModel
266         this.$scope.component.tags = _.without(this.$scope.component.tags, this.$scope.component.name);
267
268         // Init categories
269         this.$scope.initCategories();
270
271         // Init Environment Context
272         this.$scope.initEnvironmentContext();
273
274         // Init Models
275         this.$scope.initModel();
276
277         // Init the decision if to show file browse.
278         this.$scope.isShowFileBrowse = false;
279         if (this.$scope.component.isResource()) {
280             let resource:Resource = <Resource>this.$scope.component;
281             console.log(resource.name + ": " + resource.csarUUID);
282             if (resource.importedFile) { // Component has imported file.
283                 this.$scope.isShowFileBrowse = true;
284             }
285             if (resource.resourceType === ResourceType.VF && !resource.csarUUID) {
286                 this.$scope.isShowFileBrowse = true;
287             }
288         } else if (this.$scope.component.isService()) {
289             let service: Service = <Service>this.$scope.component;
290             console.log(service.name + ": " + service.csarUUID);
291             if (service.importedFile) {
292                 this.$scope.isShowFileBrowse = true;
293                 (<Service>this.$scope.component).ecompGeneratedNaming = true;
294                 let blob = this.FileUtils.base64toBlob(service.importedFile.base64, "zip");
295                 new ServiceCsarReader().read(blob).then(
296                     (serviceCsar) => {
297                         serviceCsar.serviceMetadata.contactId = this.cacheService.get("user").userId;
298                         (<Service>this.$scope.component).setComponentMetadata(serviceCsar.serviceMetadata);
299                         (<Service>this.$scope.component).model = serviceCsar.serviceMetadata.model;
300                         this.$scope.onModelChange();
301                         this.$scope.componentCategories.selectedCategory = serviceCsar.serviceMetadata.selectedCategory;
302                         this.$scope.onCategoryChange();
303                         serviceCsar.extraServiceMetadata.forEach((value: string, key: string) => {
304                             if (this.getMetadataKey(key)) {
305                                 (<Service>this.$scope.component).categorySpecificMetadata[key] = value;
306                             }
307                         });
308                         (<Service>this.$scope.component).derivedFromGenericType = serviceCsar.substitutionNodeType;
309                         this.$scope.onBaseTypeChange();
310                         this.setFunctionRole(service);
311                     },
312                     (error) => {
313                         const errorMsg = this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT');
314                         console.error(errorMsg, error);
315                         const errorDetails = {
316                             'Error': this.capitalize(error.reason),
317                             'Details': this.capitalize(error.message)
318                         };
319                         this.modalServiceSdcUI.openErrorDetailModal('Error', this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT'),
320                             'error-modal', errorDetails);
321                         this.$state.go('dashboard');
322                     });
323             }
324
325             this.setFunctionRole(service);
326
327             if (this.$scope.isEditMode() && service.serviceType == 'Service' && !service.csarUUID) {
328                 this.$scope.isShowFileBrowse = true;
329             }
330             // Init Instantiation types
331             this.$scope.initInstantiationTypes();
332             this.$scope.initBaseTypes();
333         }
334
335         if (this.cacheService.get(PREVIOUS_CSAR_COMPONENT)) { //keep the old component in the cache until checkout, so we dont need to pass it around
336             this.$scope.setOriginComponent(this.cacheService.get(PREVIOUS_CSAR_COMPONENT));
337             this.cacheService.remove(PREVIOUS_CSAR_COMPONENT);
338         }
339
340         if (this.$stateParams.componentCsar && !this.$scope.isCreateMode()) {
341             this.$scope.updateUnsavedFileFlag(true);
342             this.$scope.save();
343         }
344
345         if (this.$scope.component.isResource() &&
346             (this.$scope.component as Resource).resourceType === ResourceType.VF ||
347             (this.$scope.component as Resource).resourceType === ResourceType.PNF && (this.$scope.component as Resource).csarUUID) {
348             this.$scope.isShowOnboardingSelectionBrowse = true;
349             this.setImportedFileText();
350         } else {
351             this.$scope.isShowOnboardingSelectionBrowse = false;
352         }
353
354         //init file extensions based on the file that was imported.
355         if (this.$scope.component.isResource() && (<Resource>this.$scope.component).importedFile) {
356             let fileName:string = (<Resource>this.$scope.component).importedFile.filename;
357             let fileExtension:string = fileName.split(".").pop();
358             if (this.sdcConfig.csarFileExtension.indexOf(fileExtension.toLowerCase()) !== -1) {
359                 this.$scope.importedFileExtension = this.sdcConfig.csarFileExtension;
360                 (<Resource>this.$scope.component).importedFile.filetype = "csar";
361             } else if (this.sdcConfig.toscaFileExtension.indexOf(fileExtension.toLowerCase()) !== -1) {
362                 (<Resource>this.$scope.component).importedFile.filetype = "yaml";
363                 this.$scope.importedFileExtension = this.sdcConfig.toscaFileExtension;
364             }
365             this.$scope.restoreFile = angular.copy((<Resource>this.$scope.originComponent).importedFile); //create backup
366         } else if (this.$scope.isEditMode() && (<Resource>this.$scope.component).resourceType === ResourceType.VF) {
367             this.$scope.importedFileExtension = this.sdcConfig.csarFileExtension;
368             //(<Resource>this.$scope.component).importedFile.filetype="csar";
369         }
370
371         this.$scope.setValidState(true);
372
373         this.$scope.calculateUnique = (mainCategory:string, subCategory:string):string => {
374             let uniqueId:string = mainCategory;
375             if (subCategory) {
376                 uniqueId += "_#_" + subCategory; // Set the select category combobox to show the selected category.
377             }
378             return uniqueId;
379         };
380
381         //TODO remove this after handling contact in UI
382         if (this.$scope.isCreateMode()) {
383             this.$scope.component.contactId = this.cacheService.get("user").userId;
384             this.$scope.originComponent.contactId = this.$scope.component.contactId;
385         }
386
387         this.$scope.$on('$destroy', () => {
388             this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE);
389             this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
390         });
391
392     };
393
394     private capitalize(s) {
395         return s && s[0].toUpperCase() + s.slice(1);
396     }
397
398     private setFunctionRole = (service : Service) : void => {
399         if (!service.serviceFunction && service.componentMetadata) {
400             service.serviceFunction = service.componentMetadata.serviceFunction;
401         }
402         if (!service.serviceRole && service.componentMetadata) {
403             service.serviceRole = service.componentMetadata.serviceRole;
404         }
405         if (service.serviceFunction) {
406             const functionList : string[] = this.$scope.getMetadataKeyValidValues('Service Function');
407             if (functionList.find(value => value == service.serviceFunction) != undefined) {
408                 this.$scope.functionOption = service.serviceFunction;
409             } else {
410                 this.$scope.functionOption = 'Others';
411                 this.$scope.othersFlag = true;
412             }
413         }
414
415         if (service.serviceRole) {
416             const roleList : string[] = this.$scope.getMetadataKeyValidValues('Service Role');
417             if (roleList.find(value => value == service.serviceRole) != undefined) {
418                 this.$scope.roleOption = service.serviceRole;
419             } else {
420                 this.$scope.roleOption = 'Others';
421                 this.$scope.othersRoleFlag = true;
422             }
423         }
424     }
425
426     // Convert category string MainCategory_#_SubCategory to Array with one item (like the server except)
427     private convertCategoryStringToOneArray = ():IMainCategory[] => {
428         let tmp = this.$scope.component.selectedCategory.split("_#_");
429         let mainCategory = tmp[0];
430         let subCategory = tmp[1];
431
432         // Find the selected category and add the relevant sub category.
433         let selectedMainCategory:IMainCategory = <IMainCategory>_.find(this.$scope.categories, function (item) {
434             return item["name"] === mainCategory;
435
436         });
437
438         let mainCategoryClone = angular.copy(selectedMainCategory);
439         if (subCategory) {
440             let selectedSubcategory = <ISubCategory>_.find(selectedMainCategory.subcategories, function (item) {
441                 return item["name"] === subCategory;
442             });
443             mainCategoryClone['subcategories'] = [angular.copy(selectedSubcategory)];
444         }
445         let tmpSelected = <IMainCategory> mainCategoryClone;
446
447         let result:IMainCategory[] = [];
448         result.push(tmpSelected);
449
450         return result;
451     };
452
453     private updateComponentNameInBreadcrumbs = ():void => {
454         // update breadcrum after changing name
455         this.$scope.breadcrumbsModel[1].updateSelectedMenuItemText(this.$scope.component.getComponentSubType() + ': ' + this.$scope.component.name);
456         this.$scope.updateMenuComponentName(this.$scope.component.name);
457     };
458
459     //Find if a category is applicable for External API or not
460     private isHiddenCategory = (category: string) => {
461         let items: Array<any> = new Array<any>();
462         items = this.$scope.sdcMenu.component_workspace_menu_option[this.$scope.component.getComponentSubType()];
463         for(let index = 0; index < items.length; ++index) {
464             if ((items[index].hiddenCategories && items[index].hiddenCategories.indexOf(category) > -1)) {
465                 return true;
466             }
467         }
468         return false;
469     };
470
471     private filteredCategories = () => {
472         let tempCategories: Array<IMainCategory> = new Array<IMainCategory>();
473         this.$scope.categories.forEach((category) => {
474             if (!this.isHiddenCategory(category.name)
475                 && this.$scope.isCreateMode()
476             ) {
477                 tempCategories.push(category);
478             } else if ((ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState)
479                 && !this.isHiddenCategory(this.$scope.component.selectedCategory)
480                 && !this.isHiddenCategory(category.name)
481             ) {
482                 tempCategories.push(category);
483             } else if ((ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState)
484                 && this.isHiddenCategory(this.$scope.component.selectedCategory)) {
485                 tempCategories.push(category);
486             }
487         });
488
489         return tempCategories;
490     };
491
492     private initScopeMethods = ():void => {
493
494         this.$scope.initCategories = ():void => {
495             if (this.$scope.componentType === ComponentType.RESOURCE) {
496                 this.$scope.categories = this.cacheService.get('resourceCategories');
497
498             }
499             if (this.$scope.componentType === ComponentType.SERVICE) {
500                 this.$scope.categories = this.cacheService.get('serviceCategories');
501
502                 //Remove categories from dropdown applicable for External API
503                 if (this.$scope.isCreateMode() || (ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState)) {
504                     this.$scope.categories = this.filteredCategories();
505                     //Flag to disbale category if service is created through External API
506                     this.$scope.isHiddenCategorySelected = this.isHiddenCategory(this.$scope.component.selectedCategory);
507                 }
508
509             }
510         };
511
512         this.$scope.initInstantiationTypes = ():void => {
513             if (this.$scope.componentType === ComponentType.SERVICE) {
514                 this.$scope.instantiationTypes = new Array();
515                 this.$scope.instantiationTypes.push(instantiationType.A_LA_CARTE);
516                 this.$scope.instantiationTypes.push(instantiationType.MACRO);
517                 var instantiationTypeField:string =(<Service>this.$scope.component).instantiationType;
518                 if (instantiationTypeField === ""){
519                     this.$scope.instantiationTypes.push("");
520                 }
521                 else if (this.isCreateModeAvailable(instantiationTypeField)) {
522                     (<Service>this.$scope.component).instantiationType = instantiationType.A_LA_CARTE;
523
524                 }
525             }
526         };
527
528         this.$scope.initBaseTypes = ():void => {
529             if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.component.categories) {
530                 if (!this.$scope.component.derivedFromGenericType) {
531                     this.$scope.component.derivedFromGenericVersion = undefined;
532                     this.$scope.showBaseTypeVersions = false;
533                     return;
534                 }
535                 let modelName = this.$scope.component.model ? this.$scope.component.model : null;
536                 const categoryName = this.$scope.component.categories[0].name;
537                 this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((data: ListBaseTypesResponse) => {
538                     this.$scope.baseTypes = []
539                     this.$scope.baseTypeVersions = []
540                     this.$scope.isBaseTypeRequired = data.required;
541                     data.baseTypes.forEach(baseType => {
542                         this.$scope.baseTypes.push(baseType.toscaResourceName);
543                         if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) {
544                             baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
545                         }
546                     });
547                     this.$scope.showBaseTypeVersions = true;
548                 })
549             }
550         };
551
552         this.$scope.initModel = ():void => {
553             this.$scope.isModelRequired = false;
554             this.$scope.models = [];
555             this.$scope.defaultModelOption = DEFAULT_MODEL_NAME;
556             this.$scope.showDefaultModelOption = true;
557             if (this.$scope.componentType === ComponentType.SERVICE) {
558                 this.filterCategoriesByModel(this.$scope.component.model);
559             }
560             if (this.$scope.isCreateMode() && this.$scope.isVspImport()) {
561                 if (this.$scope.component.componentMetadata.models) {
562                     this.$scope.isModelRequired = true;
563                     const modelOptions = this.$scope.component.componentMetadata.models;
564                     if (modelOptions.length == 1) {
565                         this.$scope.models = modelOptions;
566                         this.$scope.component.model = modelOptions[0];
567                         this.$scope.showDefaultModelOption = false;
568                     } else {
569                         this.$scope.models = modelOptions.sort();
570                         this.$scope.defaultModelOption = 'Select';
571                     }
572                 }
573                 return;
574             }
575
576             if (!this.$scope.isCreateMode() && this.$scope.isVspImport()) {
577                 this.modelService.getModels().subscribe((modelsFound: Model[]) => {
578                     modelsFound.sort().forEach(model => {
579                         if (this.$scope.component.model != undefined) {
580                             if (model.modelType == "NORMATIVE_EXTENSION") {
581                                 if (this.$scope.component.model === model.name) {
582                                     this.$scope.component.model = model.derivedFrom;
583                                 }
584                                 this.$scope.models.push(model.derivedFrom)
585                             } else {
586                                 this.$scope.models.push(model.name)
587                             }
588                         }
589                     });
590                 });
591             } else {
592                 this.modelService.getModelsOfType("normative").subscribe((modelsFound: Model[]) => {
593                     modelsFound.sort().forEach(model => {
594                         this.$scope.models.push(model.name)
595                     });
596                 });
597             }
598         };
599
600         this.$scope.isVspImport = (): boolean => {
601             if (!this.$scope.component || !this.$scope.component.isResource()) {
602                 return false;
603             }
604
605             const resource = <Resource>this.$scope.component;
606             return resource.isCsarComponent();
607         }
608
609         this.$scope.initEnvironmentContext = ():void => {
610             if (this.$scope.componentType === ComponentType.SERVICE) {
611                 this.$scope.environmentContextObj = this.cacheService.get('UIConfiguration').environmentContext;
612                 var environmentContext:string =(<Service>this.$scope.component).environmentContext;
613                 // In creation new service OR check outing old service without environmentContext parameter - set default value
614                 if(this.isCreateModeAvailable(environmentContext)){
615                     (<Service>this.$scope.component).environmentContext = this.$scope.environmentContextObj.defaultValue;
616                 }
617             }
618         };
619
620         this.$scope.validateField = (field:any):boolean => {
621             if (field && field.$dirty && field.$invalid) {
622                 return true;
623             }
624             return false;
625         };
626
627         this.$scope.openOnBoardingModal = ():void => {
628             if(this.$scope.component.vspArchived) return;
629             let csarUUID = (<Resource>this.$scope.component).csarUUID;
630             let csarVersion = (<Resource>this.$scope.component).csarVersion;
631             this.importVSPService.openOnboardingModal(csarUUID, csarVersion).subscribe((result) => {
632                 this.ComponentFactory.getComponentWithMetadataFromServer(result.type.toUpperCase(), result.previousComponent.uniqueId).then(
633                     (component:Component)=> {
634                         if (result.componentCsar && component.isResource()){
635                             this.cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component));
636                             component = this.ComponentFactory.updateComponentFromCsar(result.componentCsar, <Resource>component);
637                         }
638                         this.$scope.setComponent(component);
639                         this.$scope.save();
640                         this.setImportedFileText();
641                     }, ()=> {
642                         // ERROR
643                     });
644             })
645         };
646
647         this.$scope.updateIcon = ():void => {
648             this.ModalsHandler.openUpdateIconModal(this.$scope.component).then((isDirty:boolean)=> {
649                 if(isDirty && !this.$scope.isCreateMode()){
650                     this.setUnsavedChanges(true);
651                 }
652             }, ()=> {
653                 // ERROR
654             });
655         };
656
657         this.$scope.possibleToUpdateIcon = ():boolean => {
658             if(this.$scope.componentCategories.selectedCategory && (!this.$scope.component.isResource() || this.$scope.component.vendorName) && !this.$scope.component.isAlreadyCertified()){
659                 return true;
660             }else{
661                 return false;
662             }
663         }
664
665         this.$scope.validateName = (isInit:boolean):void => {
666             if (isInit === undefined) {
667                 isInit = false;
668             }
669
670             let name = this.$scope.component.name;
671             if (!name || name === "") {
672                 if (this.$scope.editForm
673                     && this.$scope.editForm["componentName"]
674                     && this.$scope.editForm["componentName"].$error) {
675
676                     // Clear the error name already exists
677                     this.$scope.editForm["componentName"].$setValidity('nameExist', true);
678                 }
679
680                 return;
681             }
682
683             let subtype:string = ComponentType.RESOURCE == this.$scope.componentType ? this.$scope.component.getComponentSubType() : undefined;
684             if (subtype == "SRVC") {
685                 subtype = "VF"
686             }
687
688             const onFailed = (response) => {
689                 // console.info('onFaild', response);
690                 // this.$scope.isLoading = false;
691             };
692
693             const onSuccess = (validation:IValidate) => {
694                 this.$scope.editForm['componentName'].$setValidity('nameExist', validation.isValid);
695                 if (validation.isValid) {
696                     this.updateComponentNameInBreadcrumbs(); // update breadcrumb after changing name
697                 } else {
698                     this.$scope.editForm['componentName'].$setDirty();
699                 }
700             };
701
702             if (isInit) {
703                 // When page is init after update
704                 if (this.$scope.component.name !== this.$scope.originComponent.name) {
705                     if (!(this.$scope.componentType === ComponentType.RESOURCE && (<Resource>this.$scope.component).csarUUID !== undefined)
706                     ) {
707                         this.$scope.component.validateName(name, subtype).then(onSuccess, onFailed);
708                     }
709                 }
710             } else {
711                 // Validating on change (has debounce)
712                 if (this.$scope.editForm
713                     && this.$scope.editForm["componentName"]
714                     && this.$scope.editForm["componentName"].$error
715                     && !this.$scope.editForm["componentName"].$error.pattern
716                     && (!this.$scope.originComponent.name || this.$scope.component.name.toUpperCase() !== this.$scope.originComponent.name.toUpperCase())
717                 ) {
718                     if (!(this.$scope.componentType === ComponentType.RESOURCE && (this.$scope.component as Resource).csarUUID !== undefined)
719                     ) {
720                         this.$scope.component.validateName(name, subtype).then(onSuccess, onFailed);
721                     }
722                 } else if (this.$scope.editForm && this.$scope.originComponent.name && this.$scope.component.name.toUpperCase() === this.$scope.originComponent.name.toUpperCase()) {
723                     // Clear the error
724                     this.$scope.editForm['componentName'].$setValidity('nameExist', true);
725                 }
726             }
727         };
728
729         this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, (nextState) => {
730             if (this.$state.current.data.unsavedChanges && this.$scope.isValidForm) {
731                 this.$scope.save().then(() => {
732                     this.$scope.handleChangeLifecycleState(nextState);
733                 }, () => {
734                     console.error('Save failed, unable to change lifecycle state to ' + nextState);
735                 });
736             } else if(!this.$scope.isValidForm){
737                 console.error('Form is not valid');
738             } else {
739                 let newCsarVersion:string;
740                 if(this.$scope.unsavedFile) {
741                     newCsarVersion = (this.$scope.component as Resource).csarVersion;
742                 }
743                 if(this.$stateParams.componentCsar && !this.$scope.isCreateMode()) {
744                     const onError = (): void => {
745                         if (this.$scope.component.lifecycleState === 'NOT_CERTIFIED_CHECKIN') {
746                             this.$scope.revert();
747                         }
748                     };
749                     this.$scope.handleChangeLifecycleState(nextState, newCsarVersion, onError);
750
751                 } else {
752                     this.$scope.handleChangeLifecycleState(nextState, newCsarVersion);
753                 }
754             }
755         });
756
757         this.$scope.revert = ():void => {
758             // in state of import file leave the file in place
759
760             this.$scope.setComponent(this.ComponentFactory.createComponent(this.$scope.originComponent));
761
762             if (this.$scope.component.isResource() && this.$scope.restoreFile) {
763                 (this.$scope.component as Resource).importedFile = angular.copy(this.$scope.restoreFile);
764             }
765
766             this.setImportedFileText();
767             this.$scope.updateBreadcrumbs(this.$scope.component); // update on workspace
768
769             this.$scope.componentCategories.selectedCategory = this.$scope.originComponent.selectedCategory;
770             this.setUnsavedChanges(false);
771             this.$scope.updateUnsavedFileFlag(false);
772             this.$scope.editForm.$setPristine();
773         };
774
775         this.$scope.onImportFileChange = () => {
776
777             if( !this.$scope.restoreFile && this.$scope.editForm.fileElement.value && this.$scope.editForm.fileElement.value.filename || // if file started empty but we have added a new one
778                 this.$scope.restoreFile && !angular.equals(this.$scope.restoreFile, this.$scope.editForm.fileElement.value)){ // or file was swapped for a new one
779                 this.$scope.updateUnsavedFileFlag(true);
780             } else {
781                 this.$scope.updateUnsavedFileFlag(false);
782                 this.$scope.editForm.fileElement.$setPristine();
783             }
784         };
785
786         this.$scope.$watchCollection('component.name', (newData: any): void => {
787             this.$scope.validateName(false);
788         });
789
790         // Notify the parent if this step valid or not.
791         this.$scope.$watch('editForm.$valid', (newVal, oldVal) => {
792             this.$scope.setValidState(newVal);
793         });
794
795         this.$scope.$watch('editForm.$dirty', (newVal, oldVal) => {
796             if (newVal && !this.$scope.isCreateMode()) {
797                 this.setUnsavedChanges(true);
798             }
799
800         });
801
802         this.$scope.onCategoryChange = (): void => {
803             if (!this.$scope.component.selectedCategory) {
804                 this.$scope.editForm['category'].$setDirty();
805             }
806             if (!this.$scope.component.description) {
807                 this.$scope.editForm['description'].$setDirty();
808             }
809             this.$scope.component.selectedCategory = this.$scope.componentCategories.selectedCategory;
810             if (this.$scope.component.selectedCategory) {
811                 this.$scope.roleOption = null;
812                 (<Service>this.$scope.component).serviceRole = null;
813                 this.$scope.othersFlag = false;
814                 this.$scope.functionOption = null;
815                 (<Service>this.$scope.component).serviceFunction = null;
816                 this.$scope.othersRoleFlag = false;
817
818                 this.$scope.component.categories = this.convertCategoryStringToOneArray();
819                 this.$scope.component.icon = DEFAULT_ICON;
820                 if (this.$scope.component.categories[0].metadataKeys) {
821                     for (let metadataKey of this.$scope.component.categories[0].metadataKeys) {
822                         if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
823                             this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
824                         }
825                         if (metadataKey.name === 'Service Role') {
826                             if ((<Service>this.$scope.component).componentMetadata && (<Service>this.$scope.component).componentMetadata.serviceRole) {
827                                 this.$scope.roleOption = (<Service>this.$scope.component).componentMetadata.serviceRole;
828                             }
829                             else {
830                                 this.$scope.roleOption = this.$scope.component.categorySpecificMetadata[metadataKey.name];
831                             }
832                             (<Service>this.$scope.component).serviceRole = this.$scope.roleOption;
833                         }
834                         if (metadataKey.name === 'Service Function') {
835                             this.$scope.functionOption = this.$scope.component.categorySpecificMetadata[metadataKey.name];
836                         }
837                     }
838                 }
839                 if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) {
840                     for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) {
841                         if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
842                             this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : "";
843                         }
844                     }
845                 }
846                 if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component.categories[0]) {
847                     const modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
848                     this.elementService.getCategoryBaseTypes(this.$scope.component.categories[0].name, modelName)
849                     .subscribe((data: ListBaseTypesResponse) => {
850                         if (this.$scope.isCreateMode()) {
851                             this.loadBaseTypes(data);
852                         } else {
853                             let isValidForBaseType:boolean = data.baseTypes.some(baseType => {
854                                 return !this.$scope.component.derivedFromGenericType ||
855                                     baseType.toscaResourceName === this.$scope.component.derivedFromGenericType;
856                             });
857                             this.$scope.editForm['category'].$setValidity('validForBaseType', isValidForBaseType);
858                         }
859                     });
860                 }
861             } else {
862                 this.clearBaseTypes();
863             }
864         };
865
866         this.$scope.onEcompGeneratedNamingChange = (): void => {
867             if (!(this.$scope.component as Service).ecompGeneratedNaming) {
868                 (this.$scope.component as Service).namingPolicy = '';
869             }
870         };
871
872         this.$scope.getCategoryDisplayNameOrName = (mainCategory: any): string => {
873             return mainCategory.displayName ? mainCategory.displayName : mainCategory.name ;
874         }
875
876         this.$scope.onBaseTypeChange = (): void => {
877             if (!this.$scope.component.derivedFromGenericType) {
878                 this.$scope.component.derivedFromGenericVersion = undefined;
879                 this.$scope.showBaseTypeVersions = false;
880                 return;
881             }
882
883             const modelName : string = this.$scope.component.model ? this.$scope.component.model : null;
884             const categoryName = this.$scope.component.categories[0].name;
885             this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((baseTypeResponseList: ListBaseTypesResponse) => {
886                 this.$scope.baseTypeVersions = []
887                 baseTypeResponseList.baseTypes.forEach(baseType => {
888                     if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) {
889                         baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
890                         this.$scope.component.derivedFromGenericVersion = baseType.versions[0];
891                     }
892                 });
893                 this.$scope.showBaseTypeVersions = true;
894             });
895         };
896
897         this.$scope.onModelChange = (): void => {
898             if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.categories) {
899                 let modelName = this.$scope.component.model ? this.$scope.component.model : null;
900                 this.$scope.component.categories = undefined;
901                 this.$scope.component.selectedCategory = undefined;
902                 this.$scope.componentCategories.selectedCategory = undefined;
903                 this.filterCategoriesByModel(modelName);
904                 this.filterBaseTypesByModelAndCategory(modelName)
905             }
906         };
907
908         this.$scope.onVendorNameChange = (oldVendorName: string): void => {
909             if (this.$scope.component.icon === oldVendorName) {
910                 this.$scope.component.icon = DEFAULT_ICON;
911             }
912         };
913
914         this.$scope.setServiceFunction = (option:string): void => {
915             if (option === 'Others') {
916                 this.$scope.othersFlag = true;
917                 (<Service>this.$scope.component).serviceFunction = '';
918             } else {
919                 this.$scope.othersFlag = false;
920                 (<Service>this.$scope.component).serviceFunction = option;
921             }
922
923         }
924
925         this.$scope.setServiceRole = (option:string): void => {
926             if (option === 'Others') {
927                 this.$scope.othersRoleFlag = true;
928                 (<Service>this.$scope.component).serviceRole = '';
929             } else {
930                 this.$scope.othersRoleFlag = false;
931                 (<Service>this.$scope.component).serviceRole = option;
932             }
933
934         }
935
936         this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload);
937
938         this.$scope.isMetadataKeyMandatory = (key: string): boolean => {
939             let metadataKey = this.getMetadataKey(key);
940             return metadataKey && metadataKey.mandatory;
941         }
942
943         this.$scope.getMetadataKeyValidValues = (key: string): string[] => {
944             let metadataKey = this.getMetadataKey(key);
945             if (metadataKey) {
946                 if (key == 'Service Function' || key == 'Service Role') {
947                     return metadataKey.validValues.concat("Others");
948                 } else {
949                     return metadataKey.validValues;
950                 }
951             }
952             return [];
953         }
954
955         this.$scope.getMetadataDisplayName = (key: string): string => {
956             let metadataKey = this.getMetadataKey(key);
957             if (metadataKey) {
958                 return metadataKey.displayName ? metadataKey.displayName : metadataKey.name;
959             }
960             return "";
961         }
962
963         this.$scope.isMetadataKeyForComponentCategory = (key: string): boolean => {
964             return this.getMetadataKey(key) != null;
965         }
966
967         this.$scope.isCategoryServiceMetadataKey = (key: string): boolean => {
968             return this.isServiceMetadataKey(key);
969         }
970
971         this.$scope.isMetadataKeyForComponentCategoryService = (key: string, attribute: string): boolean => {
972             let metadatakey = this.getMetadataKey(key);
973             if (attribute != 'serviceFunction' && attribute != 'serviceRole') {
974                 if (metadatakey && (!this.$scope.component[attribute] || !metadatakey.validValues.find(v => v === this.$scope.component[attribute]))) {
975                     this.$scope.component[attribute] = metadatakey.defaultValue;
976                 }
977             }
978             return metadatakey != null;
979         }
980
981         this.$scope.isNotApplicableMetadataKeys = (key: string): boolean => {
982             return this.$scope.component.categories && this.$scope.component.categories[0].notApplicableMetadataKeys && this.$scope.component.categories[0].notApplicableMetadataKeys.some(item => item === key);
983         }
984     }
985
986     private filterCategoriesByModel(modelName:string) {
987         // reload categories
988         this.$scope.initCategories();
989         this.$scope.categories = this.$scope.categories.filter(category =>
990             !modelName ? !category.models || category.models.indexOf(DEFAULT_MODEL_NAME) !== -1 : category.models !== null && category.models.indexOf(modelName) !== -1);
991     }
992
993     private filterBaseTypesByModelAndCategory(modelName:string) {
994         let categories = this.$scope.component.categories;
995         if (categories) {
996             this.elementService.getCategoryBaseTypes(categories[0].name, modelName).subscribe((data: ListBaseTypesResponse) => {
997                 this.loadBaseTypes(data);
998             });
999             return;
1000         }
1001         this.clearBaseTypes();
1002     }
1003
1004     private loadBaseTypes(baseTypeResponseList: ListBaseTypesResponse) {
1005         this.$scope.isBaseTypeRequired = baseTypeResponseList.required;
1006         this.$scope.baseTypes = [];
1007         this.$scope.baseTypeVersions = [];
1008         let defaultBaseType = baseTypeResponseList.defaultBaseType;
1009         baseTypeResponseList.baseTypes.forEach(baseType => this.$scope.baseTypes.push(baseType.toscaResourceName));
1010         if (this.$scope.isBaseTypeRequired || defaultBaseType != null) {
1011             let baseType = baseTypeResponseList.baseTypes[0];
1012             if(defaultBaseType != null){
1013                 baseTypeResponseList.baseTypes.forEach(baseTypeObj => {
1014                     if(baseTypeObj.toscaResourceName == defaultBaseType) {
1015                         baseType = baseTypeObj;
1016                     }
1017                 });
1018             }
1019             if((<Service>this.$scope.component).derivedFromGenericType) {
1020                 baseTypeResponseList.baseTypes.forEach(baseTypeObj => {
1021                     if(baseTypeObj.toscaResourceName == (<Service>this.$scope.component).derivedFromGenericType) {
1022                         baseType = baseTypeObj;
1023                     }
1024                 });
1025             }
1026             baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version));
1027             this.$scope.component.derivedFromGenericType = baseType.toscaResourceName;
1028             this.$scope.component.derivedFromGenericVersion = this.$scope.baseTypeVersions[0];
1029             this.$scope.showBaseTypeVersions = true;
1030             return
1031         }
1032         this.$scope.component.derivedFromGenericType = undefined;
1033         this.$scope.component.derivedFromGenericVersion = undefined;
1034         this.$scope.showBaseTypeVersions = false;
1035     }
1036
1037     private clearBaseTypes() {
1038         this.$scope.isBaseTypeRequired = false;
1039         this.$scope.baseTypes = [];
1040         this.$scope.baseTypeVersions = [];
1041         this.$scope.component.derivedFromGenericType = undefined;
1042         this.$scope.component.derivedFromGenericVersion = undefined;
1043         this.$scope.showBaseTypeVersions = false;
1044     }
1045
1046     private setUnsavedChanges = (hasChanges: boolean): void => {
1047         this.$state.current.data.unsavedChanges = hasChanges;
1048     }
1049
1050     private getMetadataKey(key: string) : IMetadataKey {
1051         if (this.$scope.component.categories) {
1052             let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key);
1053             if (!metadataKey){
1054                 return this.getCategoryMetadataKey(this.$scope.component.categories, key);
1055             }
1056             return metadataKey;
1057         }
1058         return null;
1059     }
1060
1061     private getSubcategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
1062         if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
1063             return categories[0].subcategories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
1064         }
1065         return null;
1066     }
1067
1068     private getCategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
1069         if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
1070             return categories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
1071         }
1072         return null;
1073     }
1074
1075     private isServiceMetadataKey(key: string) : boolean {
1076         return CATEGORY_SERVICE_METADATA_KEYS.indexOf(key) > -1;
1077     }
1078
1079 }