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