X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=catalog-ui%2Fsrc%2Fapp%2Fview-models%2Fworkspace%2Ftabs%2Fgeneral%2Fgeneral-view-model.ts;h=a0e8ca93654bc2dc18bad28cd8d21ba7f64a9924;hb=4e85b1fa6daf695608024e86513a8c45509aaf71;hp=b4529700cfd4c57ccc5e5f333f0e9588387007d3;hpb=e38ef745ab296de90cb428f26348de32e4295420;p=sdc.git diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts index b4529700cf..a0e8ca9365 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,14 +20,28 @@ 'use strict'; import * as _ from "lodash"; -import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, DEFAULT_ICON, - ResourceType, ComponentState, instantiationType, ComponentFactory} from "app/utils"; -import {CacheService, EventListenerService, ProgressService, OnboardingService} from "app/services"; -import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component} from "app/models"; -import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; import {Dictionary} from "lodash"; -import { PREVIOUS_CSAR_COMPONENT } from "../../../../utils/constants"; - +import { + ComponentFactory, + ComponentState, + ComponentType, + DEFAULT_ICON, + EVENTS, + instantiationType, + ModalsHandler, + ResourceType, + ValidationUtils, + FileUtils, + ServiceCsarReader +} from "app/utils"; +import {EventListenerService, ProgressService} from "app/services"; +import {CacheService, ElementService, ModelService, ImportVSPService, OnboardingService} from "app/services-ng2"; +import {Component, IAppConfigurtaion, ICsarComponent, IMainCategory, IMetadataKey, ISubCategory, IValidate, Resource, Service} from "app/models"; +import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; +import {CATEGORY_SERVICE_METADATA_KEYS, PREVIOUS_CSAR_COMPONENT, DEFAULT_MODEL_NAME} from "../../../../utils/constants"; +import {Observable} from "rxjs"; +import {Model} from "../../../../models/model"; +import {SdcUiServices} from "onap-ui-angular/dist"; export class Validation { componentNameValidationPattern:RegExp; @@ -37,13 +51,16 @@ export class Validation { VendorNameValidationPattern:RegExp; VendorModelNumberValidationPattern:RegExp; commentValidationPattern:RegExp; - projectCodeValidationPattern:RegExp; } export class componentCategories {//categories field bind to this obj in order to solve this bug: DE242059 selectedCategory:string; } +export class componentModel { + selectedModel:string; +} + export interface IEnvironmentContext { defaultValue:string; validValues:Array; @@ -61,11 +78,17 @@ export interface IGeneralScope extends IWorkspaceViewModelScope { isShowFileBrowse:boolean; isShowOnboardingSelectionBrowse:boolean; importedToscaBrowseFileText:string; - importCsarProgressKey:string; + importCsarProProgressKey:string; browseFileLabel:string; componentCategories:componentCategories; + componentModel:componentModel; instantiationTypes:Array; isHiddenCategorySelected: boolean; + isModelRequired: boolean; + othersFlag: boolean; + functionOption: string; + othersRoleFlag: boolean; + roleOption: string; save():Promise; revert():void; @@ -77,15 +100,23 @@ export interface IGeneralScope extends IWorkspaceViewModelScope { convertCategoryStringToOneArray(category:string, subcategory:string):Array; onCategoryChange():void; onEcompGeneratedNamingChange():void; + onModelChange():void; + onBaseTypeChange():void; openOnBoardingModal():void; - initCategoreis():void; + initCategories():void; initEnvironmentContext():void; initInstantiationTypes():void; + initBaseTypes():void; onInstantiationTypeChange():void; updateIcon():void; possibleToUpdateIcon():boolean; + initModel():void; + isVspImport(): boolean; + setServiceFunction(option:string):void; + setServiceRole(option:string):void; } +// tslint:disable-next-line:max-classes-per-file export class GeneralViewModel { static '$inject' = [ @@ -99,18 +130,23 @@ export class GeneralViewModel { 'VendorModelNumberValidationPattern', 'CommentValidationPattern', 'ValidationUtils', + 'FileUtils', 'sdcConfig', - 'ProjectCodeValidationPattern', '$state', 'ModalsHandler', + 'ModalServiceSdcUI', 'EventListenerService', 'Notification', 'Sdc.Services.ProgressService', '$interval', '$filter', '$timeout', - 'Sdc.Services.OnboardingService', - 'ComponentFactory' + 'OnboardingService', + 'ComponentFactory', + 'ImportVSPService', + 'ElementService', + 'ModelService', + '$stateParams' ]; constructor(private $scope:IGeneralScope, @@ -123,27 +159,29 @@ export class GeneralViewModel { private VendorModelNumberValidationPattern:RegExp, private CommentValidationPattern:RegExp, private ValidationUtils:ValidationUtils, + private FileUtils: FileUtils, private sdcConfig:IAppConfigurtaion, - private ProjectCodeValidationPattern:RegExp, private $state:ng.ui.IStateService, private ModalsHandler:ModalsHandler, + private modalServiceSdcUI: SdcUiServices.ModalService, private EventListenerService:EventListenerService, private Notification:any, private progressService:ProgressService, protected $interval:any, private $filter:ng.IFilterService, private $timeout:ng.ITimeoutService, - private onBoardingService:OnboardingService, - private ComponentFactory:ComponentFactory) { + private onBoardingService: OnboardingService, + private ComponentFactory:ComponentFactory, + private importVSPService: ImportVSPService, + private elementService: ElementService, + private modelService: ModelService, + private $stateParams: any) { this.initScopeValidation(); this.initScopeMethods(); this.initScope(); } - - - private initScopeValidation = ():void => { this.$scope.validation = new Validation(); this.$scope.validation.componentNameValidationPattern = this.ComponentNameValidationPattern; @@ -153,13 +191,11 @@ export class GeneralViewModel { this.$scope.validation.VendorNameValidationPattern = this.VendorNameValidationPattern; this.$scope.validation.VendorModelNumberValidationPattern = this.VendorModelNumberValidationPattern; this.$scope.validation.commentValidationPattern = this.CommentValidationPattern; - this.$scope.validation.projectCodeValidationPattern = this.ProjectCodeValidationPattern; }; - private loadOnboardingFileCache = ():ng.IPromise> =>{ - + private loadOnboardingFileCache = (): Observable>> => { let onboardCsarFilesMap:Dictionary>; - let onSuccess = (vsps:Array) =>{ + let onSuccess = (vsps:Array) => { onboardCsarFilesMap = {}; _.each(vsps, (vsp:ICsarComponent)=>{ onboardCsarFilesMap[vsp.packageId] = onboardCsarFilesMap[vsp.packageId] || {}; @@ -170,8 +206,8 @@ export class GeneralViewModel { }; let onError = (): void =>{ console.log("Error getting onboarding list"); - }; - return this.onBoardingService.getOnboardingVSPs().then(onSuccess, onError); + }; + return this.onBoardingService.getOnboardingVSPs().map(onSuccess, onError); }; private setImportedFileText = ():void => { @@ -179,7 +215,7 @@ export class GeneralViewModel { if(!this.$scope.isShowOnboardingSelectionBrowse) return; //these variables makes it easier to read this logic - let csarUUID:string = (this.$scope.component).csarUUID; + let csarUUID:string = (this.$scope.component).csarUUID; let csarVersion:string = (this.$scope.component).csarVersion; let onboardCsarFilesMap:Dictionary> = this.cacheService.get('onboardCsarFilesMap'); @@ -187,21 +223,27 @@ export class GeneralViewModel { if(this.$scope.component.vspArchived){ this.$scope.importedToscaBrowseFileText = 'VSP is archived'; } else { - this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion]; + if(this.$stateParams.componentCsar && this.$scope.component.lifecycleState === 'NOT_CERTIFIED_CHECKIN' && !this.$scope.isCreateMode()) { + this.$scope.importedToscaBrowseFileText = this.$scope.originComponent.name + ' (' + (this.$scope.originComponent as Resource).csarVersion + ')'; + } else { + if (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID]) { + this.$scope.importedToscaBrowseFileText = onboardCsarFilesMap[csarUUID][csarVersion]; + } + } } } - + if(this.$scope.component.vspArchived || (onboardCsarFilesMap && onboardCsarFilesMap[csarUUID] && onboardCsarFilesMap[csarUUID][csarVersion])){ //check that the file name is already in cache assignFileName(); } else { - this.loadOnboardingFileCache().then((onboardingFiles) => { + this.loadOnboardingFileCache().subscribe((onboardingFiles) => { onboardCsarFilesMap = onboardingFiles; this.cacheService.set('onboardCsarFilesMap', onboardingFiles); assignFileName(); }, ()=> {}); } - + } isCreateModeAvailable(verifyObj:string): boolean { @@ -211,23 +253,27 @@ export class GeneralViewModel { private initScope = ():void => { - this.$scope.importCsarProgressKey = "importCsarProgressKey"; - this.$scope.browseFileLabel = this.$scope.component.isResource() && (this.$scope.component).resourceType === ResourceType.VF ? "Upload file" : "Upload VFC"; + this.$scope.browseFileLabel = (this.$scope.component.isResource() && ((this.$scope.component).resourceType === ResourceType.VF || (this.$scope.component).resourceType === 'SRVC')) || this.$scope.component.isService() ? 'Upload File:' : 'Upload VFC:'; this.$scope.progressService = this.progressService; this.$scope.componentCategories = new componentCategories(); this.$scope.componentCategories.selectedCategory = this.$scope.component.selectedCategory; + this.$scope.othersFlag = false; + this.$scope.othersRoleFlag = false; // Init UIModel this.$scope.component.tags = _.without(this.$scope.component.tags, this.$scope.component.name); // Init categories - this.$scope.initCategoreis(); + this.$scope.initCategories(); // Init Environment Context this.$scope.initEnvironmentContext(); + // Init Models + this.$scope.initModel(); + // Init the decision if to show file browse. this.$scope.isShowFileBrowse = false; if (this.$scope.component.isResource()) { @@ -236,38 +282,74 @@ export class GeneralViewModel { if (resource.importedFile) { // Component has imported file. this.$scope.isShowFileBrowse = true; } - if (this.$scope.isEditMode() && resource.resourceType == ResourceType.VF && !resource.csarUUID) { + if (resource.resourceType === ResourceType.VF && !resource.csarUUID) { + this.$scope.isShowFileBrowse = true; + } + } else if (this.$scope.component.isService()) { + let service: Service = this.$scope.component; + console.log(service.name + ": " + service.csarUUID); + if (service.importedFile) { + this.$scope.isShowFileBrowse = true; + (this.$scope.component).ecompGeneratedNaming = true; + let blob = this.FileUtils.base64toBlob(service.importedFile.base64, "zip"); + new ServiceCsarReader().read(blob).then( + (serviceCsar) => { + serviceCsar.serviceMetadata.contactId = this.cacheService.get("user").userId; + (this.$scope.component).setComponentMetadata(serviceCsar.serviceMetadata); + (this.$scope.component).model = serviceCsar.serviceMetadata.model; + this.$scope.onModelChange(); + this.$scope.componentCategories.selectedCategory = serviceCsar.serviceMetadata.selectedCategory; + this.$scope.onCategoryChange(); + serviceCsar.extraServiceMetadata.forEach((value: string, key: string) => { + if (this.getMetadataKey(key)) { + (this.$scope.component).categorySpecificMetadata[key] = value; + } + }); + (this.$scope.component).derivedFromGenericType = serviceCsar.substitutionNodeType; + this.$scope.onBaseTypeChange(); + this.setFunctionRole(service); + }, + (error) => { + const errorMsg = this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT'); + console.error(errorMsg, error); + const errorDetails = { + 'Error': this.capitalize(error.reason), + 'Details': this.capitalize(error.message) + }; + this.modalServiceSdcUI.openErrorDetailModal('Error', this.$filter('translate')('IMPORT_FAILURE_MESSAGE_TEXT'), + 'error-modal', errorDetails); + this.$state.go('dashboard'); + }); + } + + this.setFunctionRole(service); + + if (this.$scope.isEditMode() && service.serviceType == 'Service' && !service.csarUUID) { this.$scope.isShowFileBrowse = true; } - } else if(this.$scope.component.isService()){ // Init Instantiation types this.$scope.initInstantiationTypes(); + this.$scope.initBaseTypes(); } - // Work around to change the csar version - if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { - //(this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - this.cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - this.$scope.updateUnsavedFileFlag(true); - - if (!this.$scope.isViewMode() && this.cacheService.get(PREVIOUS_CSAR_COMPONENT)) { //keep the old component in the cache until checkout, so we dont need to pass it around - this.$scope.setOriginComponent(this.cacheService.get(PREVIOUS_CSAR_COMPONENT)); - this.cacheService.remove(PREVIOUS_CSAR_COMPONENT); - } + if (this.cacheService.get(PREVIOUS_CSAR_COMPONENT)) { //keep the old component in the cache until checkout, so we dont need to pass it around + this.$scope.setOriginComponent(this.cacheService.get(PREVIOUS_CSAR_COMPONENT)); + this.cacheService.remove(PREVIOUS_CSAR_COMPONENT); } + if (this.$stateParams.componentCsar && !this.$scope.isCreateMode()) { + this.$scope.updateUnsavedFileFlag(true); + this.$scope.save(); + } - // Init the decision if to show onboarding - if (this.$scope.component.isResource() && this.$scope.isEditMode() && - ((this.$scope.component).resourceType == ResourceType.VF || - (this.$scope.component).resourceType == ResourceType.PNF) - && (this.$scope.component).csarUUID) { + if (this.$scope.component.isResource() && + (this.$scope.component as Resource).resourceType === ResourceType.VF || + (this.$scope.component as Resource).resourceType === ResourceType.PNF && (this.$scope.component as Resource).csarUUID) { this.$scope.isShowOnboardingSelectionBrowse = true; this.setImportedFileText(); } else { this.$scope.isShowOnboardingSelectionBrowse = false; } - //init file extensions based on the file that was imported. if (this.$scope.component.isResource() && (this.$scope.component).importedFile) { @@ -286,8 +368,6 @@ export class GeneralViewModel { //(this.$scope.component).importedFile.filetype="csar"; } - - this.$scope.setValidState(true); this.$scope.calculateUnique = (mainCategory:string, subCategory:string):string => { @@ -304,7 +384,6 @@ export class GeneralViewModel { this.$scope.originComponent.contactId = this.$scope.component.contactId; } - this.$scope.$on('$destroy', () => { this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE); this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE); @@ -312,8 +391,34 @@ export class GeneralViewModel { }; + private capitalize(s) { + return s && s[0].toUpperCase() + s.slice(1); + } + + private setFunctionRole = (service : Service) : void => { + if (service.serviceFunction) { + const functionList : string[] = this.$scope.getMetadataKeyValidValues('Service Function'); + if (functionList.find(value => value == service.serviceFunction) != undefined) { + this.$scope.functionOption = service.serviceFunction; + } else { + this.$scope.functionOption = 'Others'; + this.$scope.othersFlag = true; + } + } + + if (service.serviceRole) { + const roleList : string[] = this.$scope.getMetadataKeyValidValues('Service Role'); + if (roleList.find(value => value == service.serviceRole) != undefined) { + this.$scope.roleOption = service.serviceRole; + } else { + this.$scope.roleOption = 'Others'; + this.$scope.othersRoleFlag = true; + } + } + } + // Convert category string MainCategory_#_SubCategory to Array with one item (like the server except) - private convertCategoryStringToOneArray = ():Array => { + private convertCategoryStringToOneArray = ():IMainCategory[] => { let tmp = this.$scope.component.selectedCategory.split("_#_"); let mainCategory = tmp[0]; let subCategory = tmp[1]; @@ -333,14 +438,14 @@ export class GeneralViewModel { } let tmpSelected = mainCategoryClone; - let result:Array = []; + let result:IMainCategory[] = []; result.push(tmpSelected); return result; }; private updateComponentNameInBreadcrumbs = ():void => { - //update breadcrum after changing name + // update breadcrum after changing name this.$scope.breadcrumbsModel[1].updateSelectedMenuItemText(this.$scope.component.getComponentSubType() + ': ' + this.$scope.component.name); this.$scope.updateMenuComponentName(this.$scope.component.name); }; @@ -376,11 +481,11 @@ export class GeneralViewModel { }); return tempCategories; - }; - + }; + private initScopeMethods = ():void => { - this.$scope.initCategoreis = ():void => { + this.$scope.initCategories = ():void => { if (this.$scope.componentType === ComponentType.RESOURCE) { this.$scope.categories = this.cacheService.get('resourceCategories'); @@ -394,7 +499,7 @@ export class GeneralViewModel { //Flag to disbale category if service is created through External API this.$scope.isHiddenCategorySelected = this.isHiddenCategory(this.$scope.component.selectedCategory); } - + } }; @@ -414,6 +519,87 @@ export class GeneralViewModel { } }; + this.$scope.initBaseTypes = ():void => { + if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.component.categories) { + if (!this.$scope.component.derivedFromGenericType) { + this.$scope.component.derivedFromGenericVersion = undefined; + this.$scope.showBaseTypeVersions = false; + return; + } + let modelName = this.$scope.component.model ? this.$scope.component.model : null; + const categoryName = this.$scope.component.categories[0].name; + this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((data: ListBaseTypesResponse) => { + this.$scope.baseTypes = [] + this.$scope.baseTypeVersions = [] + this.$scope.isBaseTypeRequired = data.required; + data.baseTypes.forEach(baseType => { + this.$scope.baseTypes.push(baseType.toscaResourceName); + if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) { + baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version)); + } + }); + this.$scope.showBaseTypeVersions = true; + }) + } + }; + + this.$scope.initModel = ():void => { + this.$scope.isModelRequired = false; + this.$scope.models = []; + this.$scope.defaultModelOption = DEFAULT_MODEL_NAME; + this.$scope.showDefaultModelOption = true; + if (this.$scope.componentType === ComponentType.SERVICE) { + this.filterCategoriesByModel(this.$scope.component.model); + } + if (this.$scope.isCreateMode() && this.$scope.isVspImport()) { + if (this.$scope.component.componentMetadata.models) { + this.$scope.isModelRequired = true; + const modelOptions = this.$scope.component.componentMetadata.models; + if (modelOptions.length == 1) { + this.$scope.models = modelOptions; + this.$scope.component.model = modelOptions[0]; + this.$scope.showDefaultModelOption = false; + } else { + this.$scope.models = modelOptions.sort(); + this.$scope.defaultModelOption = 'Select'; + } + } + return; + } + + if (!this.$scope.isCreateMode() && this.$scope.isVspImport()) { + this.modelService.getModels().subscribe((modelsFound: Model[]) => { + modelsFound.sort().forEach(model => { + if (this.$scope.component.model != undefined) { + if (model.modelType == "NORMATIVE_EXTENSION") { + if (this.$scope.component.model === model.name) { + this.$scope.component.model = model.derivedFrom; + } + this.$scope.models.push(model.derivedFrom) + } else { + this.$scope.models.push(model.name) + } + } + }); + }); + } else { + this.modelService.getModelsOfType("normative").subscribe((modelsFound: Model[]) => { + modelsFound.sort().forEach(model => { + this.$scope.models.push(model.name) + }); + }); + } + }; + + this.$scope.isVspImport = (): boolean => { + if (!this.$scope.component || !this.$scope.component.isResource()) { + return false; + } + + const resource = this.$scope.component; + return resource.isCsarComponent(); + } + this.$scope.initEnvironmentContext = ():void => { if (this.$scope.componentType === ComponentType.SERVICE) { this.$scope.environmentContextObj = this.cacheService.get('UIConfiguration').environmentContext; @@ -436,24 +622,20 @@ export class GeneralViewModel { if(this.$scope.component.vspArchived) return; let csarUUID = (this.$scope.component).csarUUID; let csarVersion = (this.$scope.component).csarVersion; - this.ModalsHandler.openOnboadrdingModal('Update', csarUUID, csarVersion).then((result)=> { - - if(result){ - this.ComponentFactory.getComponentWithMetadataFromServer(result.type.toUpperCase(), result.previousComponent.uniqueId).then( - (component:Component)=> { + this.importVSPService.openOnboardingModal(csarUUID, csarVersion).subscribe((result) => { + this.ComponentFactory.getComponentWithMetadataFromServer(result.type.toUpperCase(), result.previousComponent.uniqueId).then( + (component:Component)=> { if (result.componentCsar && component.isResource()){ this.cacheService.set(PREVIOUS_CSAR_COMPONENT, angular.copy(component)); component = this.ComponentFactory.updateComponentFromCsar(result.componentCsar, component); } - this.$scope.setComponent(component); - this.$scope.updateUnsavedFileFlag(true); + this.$scope.save(); this.setImportedFileText(); }, ()=> { // ERROR }); - } - }, () => {}); + }) }; this.$scope.updateIcon = ():void => { @@ -491,18 +673,23 @@ export class GeneralViewModel { return; } + let subtype:string = ComponentType.RESOURCE == this.$scope.componentType ? this.$scope.component.getComponentSubType() : undefined; + if (subtype == "SRVC") { + subtype = "VF" + } - let onFailed = (response) => { - //console.info('onFaild', response); - //this.$scope.isLoading = false; + const onFailed = (response) => { + // console.info('onFaild', response); + // this.$scope.isLoading = false; }; - let onSuccess = (validation:IValidate) => { - this.$scope.editForm["componentName"].$setValidity('nameExist', validation.isValid); + const onSuccess = (validation:IValidate) => { + this.$scope.editForm['componentName'].$setValidity('nameExist', validation.isValid); if (validation.isValid) { - //update breadcrumb after changing name - this.updateComponentNameInBreadcrumbs(); + this.updateComponentNameInBreadcrumbs(); // update breadcrumb after changing name + } else { + this.$scope.editForm['componentName'].$setDirty(); } }; @@ -522,48 +709,56 @@ export class GeneralViewModel { && !this.$scope.editForm["componentName"].$error.pattern && (!this.$scope.originComponent.name || this.$scope.component.name.toUpperCase() !== this.$scope.originComponent.name.toUpperCase()) ) { - if (!(this.$scope.componentType === ComponentType.RESOURCE && (this.$scope.component).csarUUID !== undefined) + if (!(this.$scope.componentType === ComponentType.RESOURCE && (this.$scope.component as Resource).csarUUID !== undefined) ) { this.$scope.component.validateName(name, subtype).then(onSuccess, onFailed); } - } else if (this.$scope.originComponent.name && this.$scope.component.name.toUpperCase() === this.$scope.originComponent.name.toUpperCase()) { + } else if (this.$scope.editForm && this.$scope.originComponent.name && this.$scope.component.name.toUpperCase() === this.$scope.originComponent.name.toUpperCase()) { // Clear the error - this.$scope.editForm["componentName"].$setValidity('nameExist', true); + this.$scope.editForm['componentName'].$setValidity('nameExist', true); } } }; - this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, (nextState) => { - if (this.$state.current.data.unsavedChanges && this.$scope.isValidForm){ + if (this.$state.current.data.unsavedChanges && this.$scope.isValidForm) { this.$scope.save().then(() => { this.$scope.handleChangeLifecycleState(nextState); }, () => { - console.error("Save failed, unable to change lifecycle state to " + nextState); + console.error('Save failed, unable to change lifecycle state to ' + nextState); }); } else if(!this.$scope.isValidForm){ - console.error("Form is not valid"); + console.error('Form is not valid'); } else { let newCsarVersion:string; - if(this.$scope.unsavedFile){ - newCsarVersion = (this.$scope.component).csarVersion; + if(this.$scope.unsavedFile) { + newCsarVersion = (this.$scope.component as Resource).csarVersion; + } + if(this.$stateParams.componentCsar && !this.$scope.isCreateMode()) { + const onError = (): void => { + if (this.$scope.component.lifecycleState === 'NOT_CERTIFIED_CHECKIN') { + this.$scope.revert(); + } + }; + this.$scope.handleChangeLifecycleState(nextState, newCsarVersion, onError); + + } else { + this.$scope.handleChangeLifecycleState(nextState, newCsarVersion); } - this.$scope.handleChangeLifecycleState(nextState, newCsarVersion); } }); - this.$scope.revert = ():void => { - //in state of import file leave the file in place + // in state of import file leave the file in place this.$scope.setComponent(this.ComponentFactory.createComponent(this.$scope.originComponent)); if (this.$scope.component.isResource() && this.$scope.restoreFile) { - (this.$scope.component).importedFile = angular.copy(this.$scope.restoreFile); - } - - this.setImportedFileText(); - this.$scope.updateBreadcrumbs(this.$scope.component); //update on workspace + (this.$scope.component as Resource).importedFile = angular.copy(this.$scope.restoreFile); + } + + this.setImportedFileText(); + this.$scope.updateBreadcrumbs(this.$scope.component); // update on workspace this.$scope.componentCategories.selectedCategory = this.$scope.originComponent.selectedCategory; this.setUnsavedChanges(false); @@ -573,8 +768,8 @@ export class GeneralViewModel { this.$scope.onImportFileChange = () => { - 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 - this.$scope.restoreFile && !angular.equals(this.$scope.restoreFile, this.$scope.editForm.fileElement.value)){ //or file was swapped for a new one + 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 + this.$scope.restoreFile && !angular.equals(this.$scope.restoreFile, this.$scope.editForm.fileElement.value)){ // or file was swapped for a new one this.$scope.updateUnsavedFileFlag(true); } else { this.$scope.updateUnsavedFileFlag(false); @@ -582,46 +777,282 @@ export class GeneralViewModel { } }; - this.$scope.$watchCollection('component.name', (newData:any):void => { + this.$scope.$watchCollection('component.name', (newData: any): void => { this.$scope.validateName(false); }); // Notify the parent if this step valid or not. - this.$scope.$watch("editForm.$valid", (newVal, oldVal) => { + this.$scope.$watch('editForm.$valid', (newVal, oldVal) => { this.$scope.setValidState(newVal); }); - this.$scope.$watch("editForm.$dirty", (newVal, oldVal) => { + this.$scope.$watch('editForm.$dirty', (newVal, oldVal) => { if (newVal && !this.$scope.isCreateMode()) { this.setUnsavedChanges(true); } }); - this.$scope.onCategoryChange = ():void => { + this.$scope.onCategoryChange = (): void => { + if (!this.$scope.component.selectedCategory) { + this.$scope.editForm['category'].$setDirty(); + } + if (!this.$scope.component.description) { + this.$scope.editForm['description'].$setDirty(); + } this.$scope.component.selectedCategory = this.$scope.componentCategories.selectedCategory; - this.$scope.component.categories = this.convertCategoryStringToOneArray(); - this.$scope.component.icon = DEFAULT_ICON; + if (this.$scope.component.selectedCategory) { + this.$scope.component.categories = this.convertCategoryStringToOneArray(); + this.$scope.component.icon = DEFAULT_ICON; + if (this.$scope.component.categories[0].metadataKeys) { + for (let metadataKey of this.$scope.component.categories[0].metadataKeys) { + if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) { + this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : ""; + } + if (metadataKey.name === 'Service Role') { + this.$scope.roleOption = this.$scope.component.categorySpecificMetadata[metadataKey.name]; + } + if (metadataKey.name === 'Service Function') { + this.$scope.functionOption = this.$scope.component.categorySpecificMetadata[metadataKey.name]; + } + } + } + if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) { + for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) { + if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) { + this.$scope.component.categorySpecificMetadata[metadataKey.name] = metadataKey.defaultValue ? metadataKey.defaultValue : ""; + } + } + } + if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component.categories[0]) { + const modelName : string = this.$scope.component.model ? this.$scope.component.model : null; + this.elementService.getCategoryBaseTypes(this.$scope.component.categories[0].name, modelName) + .subscribe((data: ListBaseTypesResponse) => { + if (this.$scope.isCreateMode()) { + this.loadBaseTypes(data); + } else { + let isValidForBaseType:boolean = data.baseTypes.some(baseType => { + return !this.$scope.component.derivedFromGenericType || + baseType.toscaResourceName === this.$scope.component.derivedFromGenericType; + }); + this.$scope.editForm['category'].$setValidity('validForBaseType', isValidForBaseType); + } + }); + } + } else { + this.clearBaseTypes(); + } + }; + + this.$scope.onEcompGeneratedNamingChange = (): void => { + if (!(this.$scope.component as Service).ecompGeneratedNaming) { + (this.$scope.component as Service).namingPolicy = ''; + } + }; + + this.$scope.getCategoryDisplayNameOrName = (mainCategory: any): string => { + return mainCategory.displayName ? mainCategory.displayName : mainCategory.name ; + } + + this.$scope.onBaseTypeChange = (): void => { + if (!this.$scope.component.derivedFromGenericType) { + this.$scope.component.derivedFromGenericVersion = undefined; + this.$scope.showBaseTypeVersions = false; + return; + } + + const modelName : string = this.$scope.component.model ? this.$scope.component.model : null; + const categoryName = this.$scope.component.categories[0].name; + this.elementService.getCategoryBaseTypes(categoryName, modelName).subscribe((baseTypeResponseList: ListBaseTypesResponse) => { + this.$scope.baseTypeVersions = [] + baseTypeResponseList.baseTypes.forEach(baseType => { + if (baseType.toscaResourceName === this.$scope.component.derivedFromGenericType) { + baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version)); + this.$scope.component.derivedFromGenericVersion = baseType.versions[0]; + } + }); + this.$scope.showBaseTypeVersions = true; + }); }; - this.$scope.onEcompGeneratedNamingChange = ():void =>{ - if(!(this.$scope.component).ecompGeneratedNaming){ - (this.$scope.component).namingPolicy = ''; + this.$scope.onModelChange = (): void => { + if (this.$scope.componentType === ComponentType.SERVICE && this.$scope.component && this.$scope.categories) { + let modelName = this.$scope.component.model ? this.$scope.component.model : null; + this.$scope.component.categories = undefined; + this.$scope.component.selectedCategory = undefined; + this.$scope.componentCategories.selectedCategory = undefined; + this.filterCategoriesByModel(modelName); + this.filterBaseTypesByModelAndCategory(modelName) } }; - this.$scope.onVendorNameChange = (oldVendorName:string):void => { + this.$scope.onVendorNameChange = (oldVendorName: string): void => { if (this.$scope.component.icon === oldVendorName) { this.$scope.component.icon = DEFAULT_ICON; } }; + + this.$scope.setServiceFunction = (option:string): void => { + if (option === 'Others') { + this.$scope.othersFlag = true; + (this.$scope.component).serviceFunction = ''; + } else { + this.$scope.othersFlag = false; + (this.$scope.component).serviceFunction = option; + } + + } + + this.$scope.setServiceRole = (option:string): void => { + if (option === 'Others') { + this.$scope.othersRoleFlag = true; + (this.$scope.component).serviceRole = ''; + } else { + this.$scope.othersRoleFlag = false; + (this.$scope.component).serviceRole = option; + } + + } + this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload); - }; + this.$scope.isMetadataKeyMandatory = (key: string): boolean => { + let metadataKey = this.getMetadataKey(key); + return metadataKey && metadataKey.mandatory; + } - private setUnsavedChanges = (hasChanges:boolean):void => { + this.$scope.getMetadataKeyValidValues = (key: string): string[] => { + let metadataKey = this.getMetadataKey(key); + if (metadataKey) { + if (key == 'Service Function' || key == 'Service Role') { + return metadataKey.validValues.concat("Others"); + } else { + return metadataKey.validValues; + } + } + return []; + } + + this.$scope.getMetadataDisplayName = (key: string): string => { + let metadataKey = this.getMetadataKey(key); + if (metadataKey) { + return metadataKey.displayName ? metadataKey.displayName : metadataKey.name; + } + return ""; + } + + this.$scope.isMetadataKeyForComponentCategory = (key: string): boolean => { + return this.getMetadataKey(key) != null; + } + + this.$scope.isCategoryServiceMetadataKey = (key: string): boolean => { + return this.isServiceMetadataKey(key); + } + + this.$scope.isMetadataKeyForComponentCategoryService = (key: string, attribute: string): boolean => { + let metadatakey = this.getMetadataKey(key); + if (metadatakey && (!this.$scope.component[attribute] || !metadatakey.validValues.find(v => v === this.$scope.component[attribute]))) { + this.$scope.component[attribute] = metadatakey.defaultValue; + } + return metadatakey != null; + } + + this.$scope.isNotApplicableMetadataKeys = (key: string): boolean => { + return this.$scope.component.categories && this.$scope.component.categories[0].notApplicableMetadataKeys && this.$scope.component.categories[0].notApplicableMetadataKeys.some(item => item === key); + } + } + + private filterCategoriesByModel(modelName:string) { + // reload categories + this.$scope.initCategories(); + this.$scope.categories = this.$scope.categories.filter(category => + !modelName ? !category.models || category.models.indexOf(DEFAULT_MODEL_NAME) !== -1 : category.models !== null && category.models.indexOf(modelName) !== -1); + } + + private filterBaseTypesByModelAndCategory(modelName:string) { + let categories = this.$scope.component.categories; + if (categories) { + this.elementService.getCategoryBaseTypes(categories[0].name, modelName).subscribe((data: ListBaseTypesResponse) => { + this.loadBaseTypes(data); + }); + return; + } + this.clearBaseTypes(); + } + + private loadBaseTypes(baseTypeResponseList: ListBaseTypesResponse) { + this.$scope.isBaseTypeRequired = baseTypeResponseList.required; + this.$scope.baseTypes = []; + this.$scope.baseTypeVersions = []; + let defaultBaseType = baseTypeResponseList.defaultBaseType; + baseTypeResponseList.baseTypes.forEach(baseType => this.$scope.baseTypes.push(baseType.toscaResourceName)); + if (this.$scope.isBaseTypeRequired || defaultBaseType != null) { + let baseType = baseTypeResponseList.baseTypes[0]; + if(defaultBaseType != null){ + baseTypeResponseList.baseTypes.forEach(baseTypeObj => { + if(baseTypeObj.toscaResourceName == defaultBaseType) { + baseType = baseTypeObj; + } + }); + } + if((this.$scope.component).derivedFromGenericType) { + baseTypeResponseList.baseTypes.forEach(baseTypeObj => { + if(baseTypeObj.toscaResourceName == (this.$scope.component).derivedFromGenericType) { + baseType = baseTypeObj; + } + }); + } + baseType.versions.reverse().forEach(version => this.$scope.baseTypeVersions.push(version)); + this.$scope.component.derivedFromGenericType = baseType.toscaResourceName; + this.$scope.component.derivedFromGenericVersion = this.$scope.baseTypeVersions[0]; + this.$scope.showBaseTypeVersions = true; + return + } + this.$scope.component.derivedFromGenericType = undefined; + this.$scope.component.derivedFromGenericVersion = undefined; + this.$scope.showBaseTypeVersions = false; + } + + private clearBaseTypes() { + this.$scope.isBaseTypeRequired = false; + this.$scope.baseTypes = []; + this.$scope.baseTypeVersions = []; + this.$scope.component.derivedFromGenericType = undefined; + this.$scope.component.derivedFromGenericVersion = undefined; + this.$scope.showBaseTypeVersions = false; + } + + private setUnsavedChanges = (hasChanges: boolean): void => { this.$state.current.data.unsavedChanges = hasChanges; - }; + } -} + private getMetadataKey(key: string) : IMetadataKey { + if (this.$scope.component.categories) { + let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key); + if (!metadataKey){ + return this.getCategoryMetadataKey(this.$scope.component.categories, key); + } + return metadataKey; + } + return null; + } + + private getSubcategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey { + if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + return categories[0].subcategories[0].metadataKeys.find(metadataKey => metadataKey.name == key); + } + return null; + } + + private getCategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey { + if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + return categories[0].metadataKeys.find(metadataKey => metadataKey.name == key); + } + return null; + } + private isServiceMetadataKey(key: string) : boolean { + return CATEGORY_SERVICE_METADATA_KEYS.indexOf(key) > -1; + } + +}