2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 import * as _ from "lodash";
22 import {Component, Inject, ViewChild} from "@angular/core";
23 import {PropertiesService} from "../../services/properties.service";
26 Component as ComponentData,
29 FilterPropertiesAssignmentData,
33 InstanceBePropertiesMap,
34 InstanceFePropertiesMap,
35 InstancePropertiesAPIMap,
42 PropertyDeclareAPIModel,
45 import {ResourceType} from "app/utils";
46 import {ComponentServiceNg2} from "../../services/component-services/component.service";
47 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
48 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
49 import {KeysPipe} from 'app/ng2/pipes/keys.pipe';
50 import {EVENTS, PROPERTY_TYPES, WorkspaceMode, PROPERTY_DATA} from "../../../utils/constants";
51 import {EventListenerService} from "app/services/event-listener-service"
52 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
53 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
54 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
55 import {HierarchyNavService} from "./services/hierarchy-nav.service";
56 import {PropertiesUtils} from "./services/properties.utils";
57 import {ComponentModeService} from "../../services/component-services/component-mode.service";
58 import {Tab, Tabs} from "../../components/ui/tabs/tabs.component";
59 import {InputsUtils} from "./services/inputs.utils";
60 import {InstanceFeDetails} from "../../../models/instance-fe-details";
61 import {SdcUiCommon, SdcUiServices} from "onap-ui-angular";
62 import {UnsavedChangesComponent} from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
63 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
64 import {ModalService} from "../../services/modal.service";
65 import {DeclareListComponent} from "./declare-list/declare-list.component";
66 import {ToscaFunctionComponent, ToscaFunctionValidationEvent} from "./tosca-function/tosca-function.component";
67 import {CapabilitiesGroup, Capability} from "../../../models/capability";
68 import {ToscaPresentationData} from "../../../models/tosca-presentation";
69 import {Observable} from "rxjs";
70 import {TranslateService} from "../../shared/translator/translate.service";
71 import {ToscaFunction} from "../../../models/tosca-function";
72 import {SubPropertyToscaFunction} from "../../../models/sub-property-tosca-function";
73 import {DeclareInputComponent} from "./declare-input/declare-input.component";
74 import {ElementService} from "../../services/element.service";
75 import {CustomToscaFunction} from "../../../models/default-custom-functions";
76 import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
78 const SERVICE_SELF_TITLE = "SELF";
80 templateUrl: './properties-assignment.page.component.html',
81 styleUrls: ['./properties-assignment.page.component.less']
83 export class PropertiesAssignmentComponent {
84 title = "Properties & Inputs";
86 component: ComponentData;
87 componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
88 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
89 customToscaFunctions: Array<CustomToscaFunction> = [];
91 propertiesNavigationData = [];
92 instancesNavigationData = [];
94 instanceFePropertiesMap: InstanceFePropertiesMap;
95 inputs: Array<InputFEModel> = [];
96 policies: Array<PolicyInstance> = [];
97 instances: Array<ComponentInstance | GroupInstance | PolicyInstance> = [];
99 propertyStructureHeader: string;
101 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
102 selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = null;
103 checkedPropertiesCount: number = 0;
104 checkedChildPropertiesCount: number = 0;
105 enableToscaFunction: boolean = false;
106 checkedToscaCount: number = 0;
108 hierarchyPropertiesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
109 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
110 displayClearSearch = false;
111 searchPropertyName: string;
113 isInputsTabSelected: boolean;
114 isPropertiesTabSelected: boolean;
115 isPoliciesTabSelected: boolean;
117 resourceIsReadonly: boolean;
118 loadingInstances: boolean = false;
119 loadingInputs: boolean = false;
120 loadingPolicies: boolean = false;
121 loadingProperties: boolean = false;
122 changedData: Array<PropertyFEModel | InputFEModel>;
123 hasChangedData: boolean;
124 isValidChangedData: boolean;
125 savingChangedData: boolean;
126 stateChangeStartUnregister: Function;
127 serviceBePropertiesMap: InstanceBePropertiesMap;
128 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
129 selectedInstance_FlattenCapabilitiesList: Capability[];
130 componentInstancePropertyMap : PropertiesGroup;
131 defaultInputName: string;
132 doNotExtendBaseType: boolean;
134 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
135 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
136 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
138 constructor(private propertiesService: PropertiesService,
139 private hierarchyNavService: HierarchyNavService,
140 private propertiesUtils: PropertiesUtils,
141 private inputsUtils: InputsUtils,
142 private componentServiceNg2: ComponentServiceNg2,
143 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
144 private propertyCreatorComponent: PropertyCreatorComponent,
145 @Inject("$stateParams") _stateParams,
146 @Inject("$scope") private $scope: ng.IScope,
147 @Inject("$state") private $state: ng.ui.IStateService,
148 @Inject("Notification") private notification: any,
149 private componentModeService: ComponentModeService,
150 private eventListenerService: EventListenerService,
151 private ModalServiceSdcUI: SdcUiServices.ModalService,
152 private modalService: ModalService,
153 private keysPipe: KeysPipe,
154 private topologyTemplateService: TopologyTemplateService,
155 private translateService: TranslateService,
156 private service: ElementService) {
158 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
159 /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time
160 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
161 this.component = _stateParams.component;
162 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
163 this.updateViewMode();
164 this.changedData = [];
165 this.updateHasChangedData();
166 this.isValidChangedData = true;
170 console.debug("==>" + this.constructor.name + ": ngOnInit");
171 this.loadingInputs = true;
172 this.loadingPolicies = true;
173 this.loadingInstances = true;
174 this.loadingProperties = true;
175 this.topologyTemplateService
176 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
177 .subscribe(response => {
178 _.forEach(response.inputs, (input: InputBEModel) => {
179 const newInput: InputFEModel = new InputFEModel(input);
180 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
181 this.inputs.push(newInput); //only push items that were declared via SDC
183 this.componentInstancePropertyMap = response.componentInstancesProperties;
184 this.loadingInputs = false;
189 this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
190 for (let customFunction of data) {
191 this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
195 this.componentServiceNg2
196 .getComponentResourcePropertiesData(this.component)
197 .subscribe(response => {
198 this.loadingPolicies = false;
200 this.instances.push(...response.componentInstances);
201 this.instances.push(...response.groupInstances);
202 this.instances.push(...response.policies);
204 if (response.componentInstances) {
205 response.componentInstances.forEach(instance => {
206 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
208 iconClass: instance.iconClass,
209 originArchived: instance.originArchived
214 _.forEach(response.policies, (policy: any) => {
215 const newPolicy: InputFEModel = new InputFEModel(policy);
216 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
217 this.policies.push(policy);
220 // add the service self instance to the top of the list.
221 const serviceInstance = new ComponentInstance();
222 serviceInstance.name = SERVICE_SELF_TITLE;
223 serviceInstance.uniqueId = this.component.uniqueId;
224 this.instances.unshift(serviceInstance);
226 _.forEach(this.instances, (instance) => {
227 this.instancesNavigationData.push(instance);
228 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
230 iconClass: instance.iconClass,
231 originArchived: instance.originArchived
234 this.loadingInstances = false;
235 if (this.instancesNavigationData[0] == undefined) {
236 this.loadingProperties = false;
238 this.selectFirstInstanceByDefault();
240 this.loadingInstances = false;
242 let modelName = this.component.model ? this.component.model : null;
243 const categoryName= this.component.categories[0].name;
244 if (this.component.categories[0].name != null && this.component.model != null) {
245 this.service.getCategoryBaseTypes(categoryName, modelName).subscribe((response: ListBaseTypesResponse) => {
246 this.doNotExtendBaseType = response.doNotExtendBaseType;
247 this.loadingProperties = false;
252 this.loadingProperties = false;
255 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
256 // stop if has changed properties
257 if (this.hasChangedData) {
258 event.preventDefault();
259 this.showUnsavedChangesAlert().then(() => {
260 this.$state.go(toState, toParams);
266 this.loadDataTypesByComponentModel(this.component.model);
270 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
271 this.stateChangeStartUnregister();
274 selectFirstInstanceByDefault = () => {
275 if (this.instancesNavigationData[0] !== undefined) {
276 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
280 updateViewMode = () => {
281 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
284 onCheckout = (component: ComponentData) => {
285 this.component = component;
286 this.updateViewMode();
289 isSelf = (): boolean => {
290 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
293 showAddProperties = (): boolean => {
294 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
296 } else if (this.hideAddProperties()) {
299 return this.isSelf();
303 hideAddProperties = (): boolean => {
304 if (this.component.isService() && this.doNotExtendBaseType && this.isSelf) {
311 disablePropertyValue = () : boolean => {
312 if (this.component.isService() && this.doNotExtendBaseType && this.isSelf()){
318 getServiceProperties() {
319 this.loadingProperties = true;
320 this.topologyTemplateService
321 .getServiceProperties(this.component.uniqueId)
322 .subscribe((response) => {
323 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
324 this.serviceBePropertiesMap[this.component.uniqueId] = response;
325 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
326 this.loadingProperties = false;
328 this.loadingProperties = false;
332 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
333 // stop if has changed properties
334 if (this.hasChangedData) {
335 this.showUnsavedChangesAlert().then((resolve) => {
336 this.changeSelectedInstance(instance)
341 this.changeSelectedInstance(instance);
344 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
345 this.selectedInstanceData = instance;
346 this.loadingProperties = true;
347 if (instance instanceof ComponentInstance) {
348 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
349 if (this.isInput(instance.originType)) {
350 this.componentInstanceServiceNg2
351 .getComponentInstanceInputs(this.component, instance)
352 .subscribe(response => {
353 instanceBePropertiesMap[instance.uniqueId] = response;
354 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
358 this.loadingProperties = false;
360 } else if (this.isSelf()) {
361 this.getServiceProperties();
363 this.componentInstanceServiceNg2
364 .getComponentInstanceProperties(this.component, instance.uniqueId)
365 .subscribe(response => {
366 instanceBePropertiesMap[instance.uniqueId] = response;
367 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
371 this.loadingProperties = false;
374 this.loadingProperties = false;
375 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
376 } else if (instance instanceof GroupInstance) {
377 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
378 this.componentInstanceServiceNg2
379 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
380 .subscribe((response) => {
381 instanceBePropertiesMap[instance.uniqueId] = response;
382 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
386 this.loadingProperties = false;
388 } else if (instance instanceof PolicyInstance) {
389 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
390 this.componentInstanceServiceNg2
391 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
392 .subscribe((response) => {
393 instanceBePropertiesMap[instance.uniqueId] = response;
394 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
398 this.loadingProperties = false;
401 this.loadingProperties = false;
404 if (this.searchPropertyName) {
407 //clear selected property from the navigation
408 this.selectedFlatProperty = new SimpleFlatProperty();
409 this.propertiesNavigationData = [];
410 this.checkedToscaCount = 0;
411 this.enableToscaFunction = false;
415 * Entry point handling response from server
417 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
418 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
419 this.checkedPropertiesCount = 0;
420 this.checkedChildPropertiesCount = 0;
423 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
424 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
425 let currentUniqueId = this.selectedInstanceData.uniqueId;
426 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
427 let isCapabilityOwnedByInstance: boolean;
428 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
429 this.selectedInstance_FlattenCapabilitiesList,
430 (result, cap: Capability) => {
431 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
432 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
433 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
434 if (cap.properties && isCapabilityOwnedByInstance) {
435 _.forEach(cap.properties, prop => {
436 if (!prop.origName) {
437 prop.origName = prop.name;
438 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
441 return result.concat(cap.properties);
445 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
446 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
447 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
448 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
450 //concatenate capabilitiesProps to all props list
451 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
452 this.checkedPropertiesCount = 0;
455 isCapabilityProperty = (prop: PropertyBEModel) => {
456 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
459 /*** VALUE CHANGE EVENTS ***/
460 dataChanged = (item: PropertyFEModel | InputFEModel) => {
462 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
463 itemHasChanged = item.hasValueObjChanged();
464 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
465 itemHasChanged = item.hasChanged();
466 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
467 itemHasChanged = item.hasDefaultValueChanged();
470 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
471 if (itemHasChanged) {
472 if (dataChangedIdx === -1) {
473 this.changedData.push(item);
476 if (dataChangedIdx !== -1) {
477 this.changedData.splice(dataChangedIdx, 1);
481 if (this.isPropertiesTabSelected) {
482 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
483 } else if (this.isInputsTabSelected) {
484 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
485 } else if (this.isPoliciesTabSelected) {
486 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
488 this.updateHasChangedData();
492 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
495 * Handle select node in navigation area, and select the row in table
497 onPropertySelectedUpdate = ($event) => {
498 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
499 this.selectedFlatProperty = $event;
500 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
501 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
505 * When user select row in table, this will prepare the hirarchy object for the tree.
507 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
508 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
509 let property = propertyRowSelectedEvent.propertyModel;
510 let instanceName = propertyRowSelectedEvent.instanceName;
511 this.propertyStructureHeader = null;
513 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
514 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
515 let simpleFlatProperty: Array<SimpleFlatProperty>;
516 if (property instanceof PropertyFEModel) {
517 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
518 } else if (property instanceof DerivedFEProperty) {
519 // Need to find parent PropertyFEModel
520 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
521 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
523 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
525 this.propertiesNavigationData = simpleFlatProperty;
528 // Update the header in the navigation tree with property name.
529 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
531 // Set selected property in table
532 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
533 this.hierarchyNavTabs.triggerTabChange('Property Structure');
537 selectInstanceRow = ($event) => {//get instance name
538 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
539 return instance.name == $event;
541 this.hierarchyNavTabs.triggerTabChange('Composition');
544 tabChanged = (event) => {
545 // stop if has changed properties
546 if (this.hasChangedData) {
547 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
548 this.showUnsavedChangesAlert().then((proceed) => {
549 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
555 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
556 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
557 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
558 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
559 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
560 this.propertyStructureHeader = null;
561 this.searchQuery = '';
565 * Select Tosca function value from defined values
567 selectToscaFunctionAndValues = (): void => {
568 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
569 if (!selectedInstanceData) {
572 this.openToscaGetFunctionModal();
575 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
576 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
577 const instanceId: string = instancesIds[0];
578 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
579 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
582 private buildCheckedInstanceProperty(): PropertyBEModel {
583 return this.buildCheckedInstanceProperties()[0];
586 private buildCheckedInstanceProperties(): PropertyBEModel[] {
587 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
588 const instanceId: string = instancesIds[0];
589 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
592 private openToscaGetFunctionModal() {
593 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
594 const modalButtons = [];
595 let disableSaveButtonFlag = true;
596 const modal = this.modalService.createCustomModal(new ModalModel(
603 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
605 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
606 if (toscaGetFunction) {
607 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
609 this.clearCheckedInstancePropertyValue();
611 this.modalService.closeCurrentModal();
613 (): boolean => { return disableSaveButtonFlag }
615 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
616 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
617 this.modalService.closeCurrentModal();
621 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
622 'property': checkedInstanceProperty,
623 'componentInstanceMap': this.componentInstanceMap,
624 'customToscaFunctions': this.customToscaFunctions
626 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
627 disableSaveButtonFlag = !validationEvent.isValid;
629 modal.instance.open();
632 private deleteToscaValue(valueJson : any, currentKey: string[]) {
633 if(currentKey.length == 1) {
634 if (Array.isArray(valueJson) && !isNaN(Number(currentKey[0]))) {
635 valueJson.splice(Number(currentKey[0]),1);
637 delete valueJson[currentKey[0]];
640 this.deleteToscaValue(valueJson[currentKey[0]],currentKey.splice(1,currentKey.length -1));
644 private clearCheckedInstancePropertyValue() {
645 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
646 const currentValue : any = checkedInstanceProperty.value;
647 checkedInstanceProperty.getInputValues = null;
648 checkedInstanceProperty.value = null;
649 checkedInstanceProperty.toscaFunction = null;
650 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
651 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
652 const parts = propertiesNameArray.split("#");
653 let currentKey = (<DerivedFEProperty>checkedInstanceProperty.input).toscaPath;
654 if (propertiesNameArray.length > 1){
655 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
656 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
658 if(currentValue !== null && currentKey.length > 0){
659 let valueJson = JSON.parse(currentValue);
660 this.deleteToscaValue(valueJson, currentKey);
661 checkedInstanceProperty.value = JSON.stringify(valueJson);
664 if (this.selectedInstanceData instanceof ComponentInstance) {
665 var toRemove = this.changedData.filter(obj => {
666 return obj.name == checkedInstanceProperty.name && obj.type == checkedInstanceProperty.type && obj.value == null;
668 const index: number = this.changedData.indexOf(toRemove[0]);
670 this.changedData.splice(index, 1);
672 this.updateInstanceProperty(checkedInstanceProperty);
673 } else if (this.selectedInstanceData instanceof GroupInstance) {
674 this.updateGroupInstanceProperty(checkedInstanceProperty);
675 } else if (this.selectedInstanceData instanceof PolicyInstance) {
676 this.updatePolicyInstanceProperty(checkedInstanceProperty);
680 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
681 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
682 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
683 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
684 const parts = propertiesName.split("#");
685 let currentKey = (<DerivedFEProperty>checkedProperty.input).toscaPath;
686 if (checkedProperty.subPropertyToscaFunctions == null){
687 checkedProperty.subPropertyToscaFunctions = [];
689 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
690 if (!subPropertyToscaFunction){
691 subPropertyToscaFunction = new SubPropertyToscaFunction();
692 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
694 subPropertyToscaFunction.toscaFunction = toscaFunction;
695 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
698 checkedProperty.subPropertyToscaFunctions = null;
699 checkedProperty.toscaFunction = toscaFunction;
701 if (this.selectedInstanceData instanceof ComponentInstance) {
702 this.updateInstanceProperty(checkedProperty);
703 } else if (this.selectedInstanceData instanceof GroupInstance) {
704 this.updateGroupInstanceProperty(checkedProperty);
705 } else if (this.selectedInstanceData instanceof PolicyInstance) {
706 this.updatePolicyInstanceProperty(checkedProperty);
710 private isComplexSchemaType(propertyType: string): boolean {
711 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
714 private isListOrMap(propertyType: string): boolean {
715 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
718 private areEqual(array1: string[], array2: string[]): boolean {
719 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
722 updateInstanceProperty(instanceProperty: PropertyBEModel) {
723 this.loadingProperties = true;
724 this.enableToscaFunction = false;
725 this.checkedToscaCount = 0;
727 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
728 this.selectedInstanceData.uniqueId, [instanceProperty])
730 this.changeSelectedInstance(this.getSelectedInstance());
732 this.loadingProperties = false;
733 console.error(error);
735 this.loadingProperties = false;
739 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
740 this.loadingProperties = true;
741 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
742 this.selectedInstanceData.uniqueId, [instanceProperty])
744 this.changeSelectedInstance(this.getSelectedInstance());
746 this.loadingProperties = false;
747 console.error(error);
749 this.loadingProperties = false;
753 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
754 this.loadingProperties = true;
755 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
756 this.selectedInstanceData.uniqueId, [instanceProperty])
758 this.changeSelectedInstance(this.getSelectedInstance());
760 this.loadingProperties = false;
761 console.error(error);
763 this.loadingProperties = false;
767 declareInput = (): void => {
768 if (this.checkedPropertiesCount == 1) {
769 this.openAddInputNameAndDeclareInputModal();
770 } else if (this.checkedPropertiesCount > 1) {
771 this.declareInputFromProperties();
775 /*** DECLARE PROPERTIES/INPUTS ***/
776 declareInputFromProperties = (inputName?: string): void => {
777 console.debug("==>" + this.constructor.name + ": declareProperties");
779 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
780 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
781 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
782 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
783 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
785 angular.forEach(instancesIds, (instanceId: string): void => {
786 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
787 if (selectedInstanceData instanceof ComponentInstance) {
788 if (!this.isInput(selectedInstanceData.originType)) {
789 // convert Property FE model -> Property BE model, extract only checked
790 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
792 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
795 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
797 } else if (selectedInstanceData instanceof GroupInstance) {
798 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
799 } else if (selectedInstanceData instanceof PolicyInstance) {
800 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
804 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
806 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
807 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
808 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
810 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
811 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
814 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
815 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
816 prop => !this.isCapabilityProperty(prop)
818 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
819 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
822 let isCapabilityPropertyChanged = false;
824 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
825 (prop: PropertyBEModel) => {
826 prop.name = prop.origName || prop.name;
827 if (this.isCapabilityProperty(prop)) {
828 isCapabilityPropertyChanged = true;
832 this.topologyTemplateService
833 .createInput(this.component, inputsToCreate, this.isSelf())
834 .subscribe((response) => {
835 this.selectInstanceRow(SERVICE_SELF_TITLE);
836 this.onInstanceSelectedUpdate(this.instances[0]);
837 this.setInputTabIndication(response.length);
838 this.checkedPropertiesCount = 0;
839 this.checkedChildPropertiesCount = 0;
840 _.forEach(response, (input: InputBEModel) => {
841 const newInput: InputFEModel = new InputFEModel(input);
842 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
843 this.inputs.push(newInput);
844 this.updatePropertyValueAfterDeclare(newInput);
846 if (isCapabilityPropertyChanged) {
847 this.reloadInstanceCapabilities();
849 }, error => {}); //ignore error
852 generateDefaultInputName = (): string => {
853 let defaultInputName: string;
854 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
855 angular.forEach(instancesIds, (instanceId: string) => {
856 let selectedProperty: PropertyBEModel = new PropertyBEModel(this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId])[0]);
857 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
858 defaultInputName = this.generateInputName(selectedInstanceData.invariantName, selectedProperty.name);
860 return defaultInputName;
863 private generateInputName = (componentName: string, propertyName: string): string => {
864 let inputName: string;
866 if (propertyName.includes("::")) {
867 propertyName = propertyName.replace(/::/g, "_");
870 inputName = componentName + "_" + propertyName;
872 inputName = propertyName;
878 private openAddInputNameAndDeclareInputModal = (): void => {
879 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
880 const modalButtons = [];
881 const modal = this.modalService.createCustomModal(new ModalModel(
888 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
890 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
892 this.declareInputFromProperties(inputName);
894 this.notification.warning({
895 message: 'Failed to set input name',
899 this.modalService.closeCurrentModal();
902 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
903 this.modalService.closeCurrentModal();
905 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultInputName()});
906 modal.instance.open();
909 declareListProperties = (): void => {
910 // get selected properties
911 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
912 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
913 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
914 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
915 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
916 let propertyNameList: Array<string> = [];
919 angular.forEach(instancesIds, (instanceId: string): void => {
921 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
922 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
924 if (selectedInstanceData instanceof ComponentInstance) {
925 if (!this.isInput(selectedInstanceData.originType)) {
926 // convert Property FE model -> Property BE model, extract only checked
927 selectedComponentInstancesProperties[instanceId] = checkedProperties;
929 selectedComponentInstancesInputs[instanceId] = checkedProperties;
931 } else if (selectedInstanceData instanceof GroupInstance) {
932 selectedGroupInstancesProperties[instanceId] = checkedProperties;
933 } else if (selectedInstanceData instanceof PolicyInstance) {
934 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
937 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
938 propertyNameList.push(property.name);
942 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
944 let modalTitle = 'Declare Properties as List Input';
945 const modal = this.modalService.createCustomModal(new ModalModel(
947 modalTitle, /* title */
952 'blue', /* css class */
953 () => { /* callback */
954 let content:any = modal.instance.dynamicContent.instance;
957 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
958 let typelist: any = PROPERTY_TYPES.LIST;
959 let uniID: any = insId;
960 let boolfalse: any = false;
961 let required: any = content.propertyModel.required;
965 "type": content.propertyModel.simpleType,
969 let schemaProp :any = {
970 "type": content.propertyModel.simpleType,
974 reglistInput.description = content.propertyModel.description;
975 reglistInput.name = content.propertyModel.name;
976 reglistInput.type = typelist;
977 reglistInput.schemaType = content.propertyModel.simpleType;
978 reglistInput.instanceUniqueId = uniID;
979 reglistInput.uniqueId = uniID;
980 reglistInput.required = required;
981 reglistInput.schema = schem;
982 reglistInput.schemaProperty = schemaProp;
985 componentInstInputsMap: content.inputsToCreate,
986 listInput: reglistInput
989 this.topologyTemplateService
990 .createListInput(this.component, input, this.isSelf())
991 .subscribe(response => {
992 this.setInputTabIndication(response.length);
993 this.checkedPropertiesCount = 0;
994 this.checkedChildPropertiesCount = 0;
995 _.forEach(response, (input: InputBEModel) => {
996 let newInput: InputFEModel = new InputFEModel(input);
997 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
998 this.inputs.push(newInput);
999 // create list input does not return updated properties info, so need to reload
1000 //this.updatePropertyValueAfterDeclare(newInput);
1001 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1002 this.changeSelectedInstance(this.selectedInstanceData);
1004 modal.instance.close();
1006 }, error => {}); //ignore error
1009 /*, getDisabled: function */
1011 new ButtonModel('Cancel', 'outline grey', () => {
1012 modal.instance.close();
1017 // 3rd arg is passed to DeclareListComponent instance
1018 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
1019 modal.instance.open();
1022 /*** DECLARE PROPERTIES/POLICIES ***/
1023 declarePropertiesToPolicies = (): void => {
1024 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
1025 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
1027 angular.forEach(instancesIds, (instanceId: string): void => {
1028 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
1029 if (selectedInstanceData instanceof ComponentInstance) {
1030 if (!this.isInput(selectedInstanceData.originType)) {
1031 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
1036 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
1037 this.loadingPolicies = true;
1039 this.topologyTemplateService
1040 .createPolicy(this.component, policiesToCreate, this.isSelf())
1041 .subscribe(response => {
1042 this.setPolicyTabIndication(response.length);
1043 this.checkedPropertiesCount = 0;
1044 this.displayPoliciesAsDeclared(response);
1045 this.loadingPolicies = false;
1050 displayPoliciesAsDeclared = (policies) => {
1051 _.forEach(policies, (policy: any) => {
1052 let newPolicy: InputFEModel = new InputFEModel(policy);
1053 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
1054 newPolicy.relatedPropertyName = policy.name;
1055 newPolicy.relatedPropertyValue = policy.value;
1056 this.updatePropertyValueAfterDeclare(newPolicy);
1057 this.policies.push(policy);
1061 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
1062 return new Promise((resolve, reject) => {
1063 if (!this.isValidChangedData) {
1064 reject('Changed data is invalid - cannot save!');
1067 if (!this.changedData.length) {
1072 // make request and its handlers
1074 let handleSuccess, handleError;
1075 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1076 if (this.isPropertiesTabSelected) {
1077 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1078 changedProp = <PropertyFEModel>changedProp;
1079 const propBE = new PropertyBEModel(changedProp);
1080 propBE.toscaPresentation = new ToscaPresentationData();
1081 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1082 propBE.value = changedProp.getJSONValue();
1083 propBE.name = changedProp.origName || changedProp.name;
1084 delete propBE.origName;
1087 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1089 if (this.selectedInstanceData instanceof ComponentInstance) {
1090 if (this.isInput(this.selectedInstanceData.originType)) {
1091 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1092 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1093 request = Observable.forkJoin(
1094 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1095 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1096 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1099 else if (changedInputsProperties.length) {
1100 request = this.componentInstanceServiceNg2
1101 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1103 else if (changedCapabilitiesProperties.length) {
1104 request = this.componentInstanceServiceNg2
1105 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1107 handleSuccess = (response) => {
1108 // reset each changed property with new value and remove it from changed properties list
1109 response.forEach((resInput) => {
1110 const changedProp = <PropertyFEModel>this.changedData.shift();
1111 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1115 if (this.isSelf()) {
1116 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1117 delete cp.constraints;
1121 request = this.componentInstanceServiceNg2
1122 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1124 handleSuccess = (response) => {
1125 // reset each changed property with new value and remove it from changed properties list
1126 response.forEach((resProp) => {
1127 const changedProp = <PropertyFEModel>this.changedData.shift();
1128 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1133 } else if (this.selectedInstanceData instanceof GroupInstance) {
1134 request = this.componentInstanceServiceNg2
1135 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1136 handleSuccess = (response) => {
1137 // reset each changed property with new value and remove it from changed properties list
1138 response.forEach((resProp) => {
1139 const changedProp = <PropertyFEModel>this.changedData.shift();
1140 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1144 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1145 request = this.componentInstanceServiceNg2
1146 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1147 handleSuccess = (response) => {
1148 // reset each changed property with new value and remove it from changed properties list
1149 response.forEach((resProp) => {
1150 const changedProp = <PropertyFEModel>this.changedData.shift();
1151 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1156 } else if (this.isInputsTabSelected) {
1158 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1159 changedInput = <InputFEModel>changedInput;
1160 const inputBE = new InputBEModel(changedInput);
1161 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1164 request = this.componentServiceNg2
1165 .updateComponentInputs(this.component, changedInputs);
1166 handleSuccess = (response) => {
1167 // reset each changed property with new value and remove it from changed properties list
1168 response.forEach((resInput) => {
1169 const changedInput = <InputFEModel>this.changedData.shift();
1170 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1171 changedInput.required = resInput.required;
1172 changedInput.requiredOrig = resInput.required;
1177 this.savingChangedData = true;
1180 this.savingChangedData = false;
1181 if (changedCapabilitiesProperties.length) {
1182 this.reloadInstanceCapabilities();
1184 handleSuccess && handleSuccess(response);
1185 this.updateHasChangedData();
1189 this.savingChangedData = false;
1190 handleError && handleError(error);
1191 this.updateHasChangedData();
1198 reloadInstanceCapabilities = (): void => {
1199 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1200 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1201 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1202 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1203 return instance.capabilities;
1206 }, new CapabilitiesGroup());
1207 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1211 reverseChangedData = ():void => {
1212 // make reverse item handler
1213 let handleReverseItem;
1214 if (this.isPropertiesTabSelected) {
1215 handleReverseItem = (changedItem) => {
1216 changedItem = <PropertyFEModel>changedItem;
1217 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1219 } else if (this.isInputsTabSelected) {
1220 handleReverseItem = (changedItem) => {
1221 changedItem = <InputFEModel>changedItem;
1222 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1223 changedItem.resetMetadata();
1224 changedItem.required = changedItem.requiredOrig;
1228 this.changedData.forEach(handleReverseItem);
1229 this.changedData = [];
1230 this.updateHasChangedData();
1233 updateHasChangedData = ():boolean => {
1234 const curHasChangedData:boolean = (this.changedData.length > 0);
1235 if (curHasChangedData !== this.hasChangedData) {
1236 this.hasChangedData = curHasChangedData;
1237 if(this.hasChangedData) {
1238 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1240 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1243 return this.hasChangedData;
1246 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1247 this.saveChangedData().then(
1249 this.notification.success({
1250 message: 'Successfully saved changes',
1253 if(onSuccessFunction) onSuccessFunction();
1256 this.notification.error({
1257 message: 'Failed to save changes!',
1260 if(onError) onError();
1265 showUnsavedChangesAlert = ():Promise<any> => {
1266 let modalTitle:string;
1267 if (this.isPropertiesTabSelected) {
1268 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1269 } else if (this.isInputsTabSelected) {
1270 modalTitle = `Unsaved inputs for ${this.component.name}`;
1273 return new Promise<any>((resolve, reject) => {
1274 const modal = this.ModalServiceSdcUI.openCustomModal(
1278 type: SdcUiCommon.ModalType.custom,
1279 testId: "navigate-modal",
1282 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1283 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1284 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1285 ] as SdcUiCommon.IModalButtonComponent[]
1286 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1291 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1292 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1293 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1294 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1295 return feProperty.name == input.relatedPropertyName &&
1296 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1298 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1299 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1300 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1301 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1305 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1306 updateCheckedPropertyCount = (increment: boolean): void => {
1307 this.checkedPropertiesCount += (increment) ? 1 : -1;
1308 this.checkedToscaCount = 0;
1309 this.enableToscaFunction = false;
1310 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1313 updateCheckedChildPropertyCount = (increment: boolean): void => {
1314 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1317 togggleToscaBtn = (toscaFlag: boolean) : void => {
1318 this.checkedToscaCount += toscaFlag ? 1 : -1;
1319 if(this.checkedToscaCount == 1){
1320 this.enableToscaFunction = true;
1322 this.enableToscaFunction = false;
1326 setInputTabIndication = (numInputs: number): void => {
1327 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1330 setPolicyTabIndication = (numPolicies: number): void => {
1331 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1334 resetUnsavedChangesForInput = (input:InputFEModel) => {
1335 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1336 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1337 this.updateHasChangedData();
1340 deleteInput = (input: InputFEModel) => {
1341 //reset any unsaved changes to the input before deleting it
1342 this.resetUnsavedChangesForInput(input);
1344 console.debug("==>" + this.constructor.name + ": deleteInput");
1345 let inputToDelete = new InputBEModel(input);
1347 this.componentServiceNg2
1348 .deleteInput(this.component, inputToDelete)
1349 .subscribe(response => {
1350 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1352 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1353 this.changeSelectedInstance(this.selectedInstanceData);
1354 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1356 // if (instanceFeProperties) {
1357 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1358 // return prop.name == input.propertyName;
1361 // if (propToEnable) {
1362 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1363 // propToEnable.setNonDeclared(response.inputPath);
1364 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1365 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1368 }, error => {}); //ignore error
1371 deletePolicy = (policy: PolicyInstance) => {
1372 this.loadingPolicies = true;
1373 this.topologyTemplateService
1374 .deletePolicy(this.component, policy)
1375 .subscribe((response) => {
1376 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1377 this.changeSelectedInstance(this.selectedInstanceData);
1378 this.loadingPolicies = false;
1382 deleteProperty = (property: PropertyFEModel) => {
1383 const propertyToDelete = new PropertyFEModel(property);
1384 this.loadingProperties = true;
1385 const feMap = this.instanceFePropertiesMap;
1386 this.topologyTemplateService
1387 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1388 .subscribe((response) => {
1389 const props = feMap[this.component.uniqueId];
1390 props.splice(props.findIndex(p => p.uniqueId === response),1);
1391 this.loadingProperties = false;
1393 this.loadingProperties = false;
1394 console.error(error);
1398 /*** addProperty ***/
1399 addProperty = (model: string) => {
1400 this.loadDataTypesByComponentModel(model)
1401 let modalTitle = 'Add Property';
1402 let modal = this.modalService.createCustomModal(new ModalModel(
1407 new ButtonModel('Save', 'blue', () => {
1408 modal.instance.dynamicContent.instance.isLoading = true;
1409 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1410 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1411 .subscribe((response) => {
1412 modal.instance.dynamicContent.instance.isLoading = false;
1413 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1414 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1415 modal.instance.close();
1417 modal.instance.dynamicContent.instance.isLoading = false;
1418 this.notification.error({
1419 message: 'Failed to add property:' + error,
1423 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1424 new ButtonModel('Cancel', 'outline grey', () => {
1425 modal.instance.close();
1430 modal.instance.open();
1431 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1436 let modalTitle = 'Add Input';
1437 let modal = this.modalService.createCustomModal(new ModalModel(
1442 new ButtonModel('Save', 'blue', () => {
1443 modal.instance.dynamicContent.instance.isLoading = true;
1444 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1445 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1446 .subscribe((response) => {
1447 modal.instance.dynamicContent.instance.isLoading = false;
1448 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1449 this.inputs.push(newInputProp);
1450 modal.instance.close();
1452 modal.instance.dynamicContent.instance.isLoading = false;
1453 this.notification.error({
1454 message: 'Failed to add input:' + error,
1458 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1459 new ButtonModel('Cancel', 'outline grey', () => {
1460 modal.instance.close();
1465 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1466 modal.instance.open();
1469 /*** SEARCH RELATED FUNCTIONS ***/
1470 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1471 let instanceBePropertiesMap:InstanceBePropertiesMap;
1472 this.componentServiceNg2
1473 .filterComponentInstanceProperties(this.component, filterData)
1474 .subscribe((response) => {
1475 this.processInstancePropertiesResponse(response, false);
1476 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1477 this.searchPropertyName = filterData.propertyName;//mark in table
1478 this.hierarchyNavTabs.triggerTabChange('Composition');
1479 this.propertiesNavigationData = [];
1480 this.displayClearSearch = true;
1481 }, (error) => {}); //ignore error
1485 clearSearch = () => {
1486 this.instancesNavigationData = this.instances;
1487 this.searchPropertyName = "";
1488 this.hierarchyPropertiesDisplayOptions.searchText = "";
1489 this.displayClearSearch = false;
1490 this.advanceSearch.clearAll();
1491 this.searchQuery = '';
1494 clickOnClearSearch = () => {
1496 this.selectFirstInstanceByDefault();
1497 this.hierarchyNavTabs.triggerTabChange('Composition');
1500 private isInput = (instanceType:string):boolean =>{
1501 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1504 loadDataTypesByComponentModel(model:string) {
1505 this.propertyCreatorComponent.filterDataTypesByModel(model);