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 {CustomToscaFunction} from "../../../models/default-custom-functions";
75 import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
77 const SERVICE_SELF_TITLE = "SELF";
79 templateUrl: './properties-assignment.page.component.html',
80 styleUrls: ['./properties-assignment.page.component.less']
82 export class PropertiesAssignmentComponent {
83 title = "Properties & Inputs";
85 component: ComponentData;
86 componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
87 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
88 customToscaFunctions: Array<CustomToscaFunction> = [];
90 propertiesNavigationData = [];
91 instancesNavigationData = [];
93 instanceFePropertiesMap: InstanceFePropertiesMap;
94 inputs: Array<InputFEModel> = [];
95 policies: Array<PolicyInstance> = [];
96 instances: Array<ComponentInstance | GroupInstance | PolicyInstance> = [];
98 propertyStructureHeader: string;
100 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
101 selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = null;
102 checkedPropertiesCount: number = 0;
103 checkedChildPropertiesCount: number = 0;
104 enableToscaFunction: boolean = false;
105 checkedToscaCount: number = 0;
107 hierarchyPropertiesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
108 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
109 displayClearSearch = false;
110 searchPropertyName: string;
112 isInputsTabSelected: boolean;
113 isPropertiesTabSelected: boolean;
114 isPoliciesTabSelected: boolean;
116 resourceIsReadonly: boolean;
117 loadingInstances: boolean = false;
118 loadingInputs: boolean = false;
119 loadingPolicies: boolean = false;
120 loadingProperties: boolean = false;
121 changedData: Array<PropertyFEModel | InputFEModel>;
122 hasChangedData: boolean;
123 isValidChangedData: boolean;
124 savingChangedData: boolean;
125 stateChangeStartUnregister: Function;
126 serviceBePropertiesMap: InstanceBePropertiesMap;
127 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
128 selectedInstance_FlattenCapabilitiesList: Capability[];
129 componentInstancePropertyMap : PropertiesGroup;
130 defaultInputName: string;
132 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
133 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
134 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
136 constructor(private propertiesService: PropertiesService,
137 private hierarchyNavService: HierarchyNavService,
138 private propertiesUtils: PropertiesUtils,
139 private inputsUtils: InputsUtils,
140 private componentServiceNg2: ComponentServiceNg2,
141 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
142 private propertyCreatorComponent: PropertyCreatorComponent,
143 @Inject("$stateParams") _stateParams,
144 @Inject("$scope") private $scope: ng.IScope,
145 @Inject("$state") private $state: ng.ui.IStateService,
146 @Inject("Notification") private notification: any,
147 private componentModeService: ComponentModeService,
148 private eventListenerService: EventListenerService,
149 private ModalServiceSdcUI: SdcUiServices.ModalService,
150 private modalService: ModalService,
151 private keysPipe: KeysPipe,
152 private topologyTemplateService: TopologyTemplateService,
153 private translateService: TranslateService) {
155 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
156 /* 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
157 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
158 this.component = _stateParams.component;
159 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
160 this.updateViewMode();
161 this.changedData = [];
162 this.updateHasChangedData();
163 this.isValidChangedData = true;
167 console.debug("==>" + this.constructor.name + ": ngOnInit");
168 this.loadingInputs = true;
169 this.loadingPolicies = true;
170 this.loadingInstances = true;
171 this.loadingProperties = true;
172 this.topologyTemplateService
173 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
174 .subscribe(response => {
175 _.forEach(response.inputs, (input: InputBEModel) => {
176 const newInput: InputFEModel = new InputFEModel(input);
177 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
178 this.inputs.push(newInput); //only push items that were declared via SDC
180 this.componentInstancePropertyMap = response.componentInstancesProperties;
181 this.loadingInputs = false;
186 this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
187 for (let customFunction of data) {
188 this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
192 this.componentServiceNg2
193 .getComponentResourcePropertiesData(this.component)
194 .subscribe(response => {
195 this.loadingPolicies = false;
197 this.instances.push(...response.componentInstances);
198 this.instances.push(...response.groupInstances);
199 this.instances.push(...response.policies);
201 if (response.componentInstances) {
202 response.componentInstances.forEach(instance => {
203 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
205 iconClass: instance.iconClass,
206 originArchived: instance.originArchived
211 _.forEach(response.policies, (policy: any) => {
212 const newPolicy: InputFEModel = new InputFEModel(policy);
213 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
214 this.policies.push(policy);
217 // add the service self instance to the top of the list.
218 const serviceInstance = new ComponentInstance();
219 serviceInstance.name = SERVICE_SELF_TITLE;
220 serviceInstance.uniqueId = this.component.uniqueId;
221 this.instances.unshift(serviceInstance);
223 _.forEach(this.instances, (instance) => {
224 this.instancesNavigationData.push(instance);
225 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
227 iconClass: instance.iconClass,
228 originArchived: instance.originArchived
231 this.loadingInstances = false;
232 if (this.instancesNavigationData[0] == undefined) {
233 this.loadingProperties = false;
235 this.selectFirstInstanceByDefault();
237 this.loadingInstances = false;
240 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
241 // stop if has changed properties
242 if (this.hasChangedData) {
243 event.preventDefault();
244 this.showUnsavedChangesAlert().then(() => {
245 this.$state.go(toState, toParams);
251 this.loadDataTypesByComponentModel(this.component.model);
255 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
256 this.stateChangeStartUnregister();
259 selectFirstInstanceByDefault = () => {
260 if (this.instancesNavigationData[0] !== undefined) {
261 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
265 updateViewMode = () => {
266 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
269 onCheckout = (component: ComponentData) => {
270 this.component = component;
271 this.updateViewMode();
274 isSelf = (): boolean => {
275 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
278 showAddProperties = (): boolean => {
279 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
282 return this.isSelf();
285 getServiceProperties() {
286 this.loadingProperties = true;
287 this.topologyTemplateService
288 .getServiceProperties(this.component.uniqueId)
289 .subscribe((response) => {
290 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
291 this.serviceBePropertiesMap[this.component.uniqueId] = response;
292 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
293 this.loadingProperties = false;
295 this.loadingProperties = false;
299 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
300 // stop if has changed properties
301 if (this.hasChangedData) {
302 this.showUnsavedChangesAlert().then((resolve) => {
303 this.changeSelectedInstance(instance)
308 this.changeSelectedInstance(instance);
311 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
312 this.selectedInstanceData = instance;
313 this.loadingProperties = true;
314 if (instance instanceof ComponentInstance) {
315 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
316 if (this.isInput(instance.originType)) {
317 this.componentInstanceServiceNg2
318 .getComponentInstanceInputs(this.component, instance)
319 .subscribe(response => {
320 instanceBePropertiesMap[instance.uniqueId] = response;
321 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
325 this.loadingProperties = false;
327 } else if (this.isSelf()) {
328 this.getServiceProperties();
330 this.componentInstanceServiceNg2
331 .getComponentInstanceProperties(this.component, instance.uniqueId)
332 .subscribe(response => {
333 instanceBePropertiesMap[instance.uniqueId] = response;
334 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
338 this.loadingProperties = false;
341 this.loadingProperties = false;
342 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
343 } else if (instance instanceof GroupInstance) {
344 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
345 this.componentInstanceServiceNg2
346 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
347 .subscribe((response) => {
348 instanceBePropertiesMap[instance.uniqueId] = response;
349 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
353 this.loadingProperties = false;
355 } else if (instance instanceof PolicyInstance) {
356 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
357 this.componentInstanceServiceNg2
358 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
359 .subscribe((response) => {
360 instanceBePropertiesMap[instance.uniqueId] = response;
361 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
365 this.loadingProperties = false;
368 this.loadingProperties = false;
371 if (this.searchPropertyName) {
374 //clear selected property from the navigation
375 this.selectedFlatProperty = new SimpleFlatProperty();
376 this.propertiesNavigationData = [];
377 this.checkedToscaCount = 0;
378 this.enableToscaFunction = false;
382 * Entry point handling response from server
384 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
385 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
386 this.checkedPropertiesCount = 0;
387 this.checkedChildPropertiesCount = 0;
390 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
391 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
392 let currentUniqueId = this.selectedInstanceData.uniqueId;
393 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
394 let isCapabilityOwnedByInstance: boolean;
395 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
396 this.selectedInstance_FlattenCapabilitiesList,
397 (result, cap: Capability) => {
398 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
399 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
400 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
401 if (cap.properties && isCapabilityOwnedByInstance) {
402 _.forEach(cap.properties, prop => {
403 if (!prop.origName) {
404 prop.origName = prop.name;
405 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
408 return result.concat(cap.properties);
412 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
413 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
414 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
415 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
417 //concatenate capabilitiesProps to all props list
418 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
419 this.checkedPropertiesCount = 0;
422 isCapabilityProperty = (prop: PropertyBEModel) => {
423 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
426 /*** VALUE CHANGE EVENTS ***/
427 dataChanged = (item: PropertyFEModel | InputFEModel) => {
429 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
430 itemHasChanged = item.hasValueObjChanged();
431 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
432 itemHasChanged = item.hasChanged();
433 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
434 itemHasChanged = item.hasDefaultValueChanged();
437 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
438 if (itemHasChanged) {
439 if (dataChangedIdx === -1) {
440 this.changedData.push(item);
443 if (dataChangedIdx !== -1) {
444 this.changedData.splice(dataChangedIdx, 1);
448 if (this.isPropertiesTabSelected) {
449 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
450 } else if (this.isInputsTabSelected) {
451 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
452 } else if (this.isPoliciesTabSelected) {
453 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
455 this.updateHasChangedData();
459 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
462 * Handle select node in navigation area, and select the row in table
464 onPropertySelectedUpdate = ($event) => {
465 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
466 this.selectedFlatProperty = $event;
467 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
468 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
472 * When user select row in table, this will prepare the hirarchy object for the tree.
474 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
475 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
476 let property = propertyRowSelectedEvent.propertyModel;
477 let instanceName = propertyRowSelectedEvent.instanceName;
478 this.propertyStructureHeader = null;
480 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
481 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
482 let simpleFlatProperty: Array<SimpleFlatProperty>;
483 if (property instanceof PropertyFEModel) {
484 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
485 } else if (property instanceof DerivedFEProperty) {
486 // Need to find parent PropertyFEModel
487 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
488 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
490 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
492 this.propertiesNavigationData = simpleFlatProperty;
495 // Update the header in the navigation tree with property name.
496 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
498 // Set selected property in table
499 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
500 this.hierarchyNavTabs.triggerTabChange('Property Structure');
504 selectInstanceRow = ($event) => {//get instance name
505 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
506 return instance.name == $event;
508 this.hierarchyNavTabs.triggerTabChange('Composition');
511 tabChanged = (event) => {
512 // stop if has changed properties
513 if (this.hasChangedData) {
514 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
515 this.showUnsavedChangesAlert().then((proceed) => {
516 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
522 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
523 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
524 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
525 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
526 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
527 this.propertyStructureHeader = null;
528 this.searchQuery = '';
532 * Select Tosca function value from defined values
534 selectToscaFunctionAndValues = (): void => {
535 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
536 if (!selectedInstanceData) {
539 this.openToscaGetFunctionModal();
542 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
543 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
544 const instanceId: string = instancesIds[0];
545 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
546 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
549 private buildCheckedInstanceProperty(): PropertyBEModel {
550 return this.buildCheckedInstanceProperties()[0];
553 private buildCheckedInstanceProperties(): PropertyBEModel[] {
554 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
555 const instanceId: string = instancesIds[0];
556 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
559 private openToscaGetFunctionModal() {
560 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
561 const modalButtons = [];
562 let disableSaveButtonFlag = true;
563 const modal = this.modalService.createCustomModal(new ModalModel(
570 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
572 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
573 if (toscaGetFunction) {
574 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
576 this.clearCheckedInstancePropertyValue();
578 this.modalService.closeCurrentModal();
580 (): boolean => { return disableSaveButtonFlag }
582 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
583 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
584 this.modalService.closeCurrentModal();
588 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
589 'property': checkedInstanceProperty,
590 'componentInstanceMap': this.componentInstanceMap,
591 'customToscaFunctions': this.customToscaFunctions
593 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
594 disableSaveButtonFlag = !validationEvent.isValid;
596 modal.instance.open();
599 private deleteToscaValue(valueJson : any, currentKey: string[]) {
600 if(currentKey.length == 1) {
601 if (Array.isArray(valueJson) && !isNaN(Number(currentKey[0]))) {
602 valueJson.splice(Number(currentKey[0]),1);
604 delete valueJson[currentKey[0]];
607 this.deleteToscaValue(valueJson[currentKey[0]],currentKey.splice(1,currentKey.length -1));
611 private clearCheckedInstancePropertyValue() {
612 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
613 const currentValue : any = checkedInstanceProperty.value;
614 checkedInstanceProperty.getInputValues = null;
615 checkedInstanceProperty.value = null;
616 checkedInstanceProperty.toscaFunction = null;
617 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
618 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
619 const parts = propertiesNameArray.split("#");
620 let currentKey = (<DerivedFEProperty>checkedInstanceProperty.input).toscaPath;
621 if (propertiesNameArray.length > 1){
622 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
623 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
625 if(currentValue !== null && currentKey.length > 0){
626 let valueJson = JSON.parse(currentValue);
627 this.deleteToscaValue(valueJson, currentKey);
628 checkedInstanceProperty.value = JSON.stringify(valueJson);
631 if (this.selectedInstanceData instanceof ComponentInstance) {
632 var toRemove = this.changedData.filter(obj => {
633 return obj.name == checkedInstanceProperty.name && obj.type == checkedInstanceProperty.type && obj.value == null;
635 const index: number = this.changedData.indexOf(toRemove[0]);
637 this.changedData.splice(index, 1);
639 this.updateInstanceProperty(checkedInstanceProperty);
640 } else if (this.selectedInstanceData instanceof GroupInstance) {
641 this.updateGroupInstanceProperty(checkedInstanceProperty);
642 } else if (this.selectedInstanceData instanceof PolicyInstance) {
643 this.updatePolicyInstanceProperty(checkedInstanceProperty);
647 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
648 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
649 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
650 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
651 const parts = propertiesName.split("#");
652 let currentKey = (<DerivedFEProperty>checkedProperty.input).toscaPath;
653 if (checkedProperty.subPropertyToscaFunctions == null){
654 checkedProperty.subPropertyToscaFunctions = [];
656 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
657 if (!subPropertyToscaFunction){
658 subPropertyToscaFunction = new SubPropertyToscaFunction();
659 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
661 subPropertyToscaFunction.toscaFunction = toscaFunction;
662 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
665 checkedProperty.subPropertyToscaFunctions = null;
666 checkedProperty.toscaFunction = toscaFunction;
668 if (this.selectedInstanceData instanceof ComponentInstance) {
669 this.updateInstanceProperty(checkedProperty);
670 } else if (this.selectedInstanceData instanceof GroupInstance) {
671 this.updateGroupInstanceProperty(checkedProperty);
672 } else if (this.selectedInstanceData instanceof PolicyInstance) {
673 this.updatePolicyInstanceProperty(checkedProperty);
677 private isComplexSchemaType(propertyType: string): boolean {
678 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
681 private isListOrMap(propertyType: string): boolean {
682 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
685 private areEqual(array1: string[], array2: string[]): boolean {
686 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
689 updateInstanceProperty(instanceProperty: PropertyBEModel) {
690 this.loadingProperties = true;
691 this.enableToscaFunction = false;
692 this.checkedToscaCount = 0;
694 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
695 this.selectedInstanceData.uniqueId, [instanceProperty])
697 this.changeSelectedInstance(this.getSelectedInstance());
699 this.loadingProperties = false;
700 console.error(error);
702 this.loadingProperties = false;
706 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
707 this.loadingProperties = true;
708 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
709 this.selectedInstanceData.uniqueId, [instanceProperty])
711 this.changeSelectedInstance(this.getSelectedInstance());
713 this.loadingProperties = false;
714 console.error(error);
716 this.loadingProperties = false;
720 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
721 this.loadingProperties = true;
722 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
723 this.selectedInstanceData.uniqueId, [instanceProperty])
725 this.changeSelectedInstance(this.getSelectedInstance());
727 this.loadingProperties = false;
728 console.error(error);
730 this.loadingProperties = false;
734 declareInput = (): void => {
735 if (this.checkedPropertiesCount == 1) {
736 this.openAddInputNameAndDeclareInputModal();
737 } else if (this.checkedPropertiesCount > 1) {
738 this.declareInputFromProperties();
742 /*** DECLARE PROPERTIES/INPUTS ***/
743 declareInputFromProperties = (inputName?: string): void => {
744 console.debug("==>" + this.constructor.name + ": declareProperties");
746 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
747 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
748 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
749 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
750 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
752 angular.forEach(instancesIds, (instanceId: string): void => {
753 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
754 if (selectedInstanceData instanceof ComponentInstance) {
755 if (!this.isInput(selectedInstanceData.originType)) {
756 // convert Property FE model -> Property BE model, extract only checked
757 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
759 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
762 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
764 } else if (selectedInstanceData instanceof GroupInstance) {
765 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
766 } else if (selectedInstanceData instanceof PolicyInstance) {
767 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
771 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
773 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
774 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
775 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
777 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
778 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
781 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
782 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
783 prop => !this.isCapabilityProperty(prop)
785 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
786 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
789 let isCapabilityPropertyChanged = false;
791 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
792 (prop: PropertyBEModel) => {
793 prop.name = prop.origName || prop.name;
794 if (this.isCapabilityProperty(prop)) {
795 isCapabilityPropertyChanged = true;
799 this.topologyTemplateService
800 .createInput(this.component, inputsToCreate, this.isSelf())
801 .subscribe((response) => {
802 this.selectInstanceRow(SERVICE_SELF_TITLE);
803 this.onInstanceSelectedUpdate(this.instances[0]);
804 this.setInputTabIndication(response.length);
805 this.checkedPropertiesCount = 0;
806 this.checkedChildPropertiesCount = 0;
807 _.forEach(response, (input: InputBEModel) => {
808 const newInput: InputFEModel = new InputFEModel(input);
809 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
810 this.inputs.push(newInput);
811 this.updatePropertyValueAfterDeclare(newInput);
813 if (isCapabilityPropertyChanged) {
814 this.reloadInstanceCapabilities();
816 }, error => {}); //ignore error
819 generateDefaultInputName = (): string => {
820 let defaultInputName: string;
821 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
822 angular.forEach(instancesIds, (instanceId: string) => {
823 let selectedProperty: PropertyBEModel = new PropertyBEModel(this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId])[0]);
824 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
825 defaultInputName = this.generateInputName(selectedInstanceData.invariantName, selectedProperty.name);
827 return defaultInputName;
830 private generateInputName = (componentName: string, propertyName: string): string => {
831 let inputName: string;
833 if (propertyName.includes("::")) {
834 propertyName = propertyName.replace(/::/g, "_");
837 inputName = componentName + "_" + propertyName;
839 inputName = propertyName;
845 private openAddInputNameAndDeclareInputModal = (): void => {
846 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
847 const modalButtons = [];
848 const modal = this.modalService.createCustomModal(new ModalModel(
855 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
857 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
859 this.declareInputFromProperties(inputName);
861 this.notification.warning({
862 message: 'Failed to set input name',
866 this.modalService.closeCurrentModal();
869 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
870 this.modalService.closeCurrentModal();
872 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultInputName()});
873 modal.instance.open();
876 declareListProperties = (): void => {
877 // get selected properties
878 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
879 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
880 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
881 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
882 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
883 let propertyNameList: Array<string> = [];
886 angular.forEach(instancesIds, (instanceId: string): void => {
888 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
889 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
891 if (selectedInstanceData instanceof ComponentInstance) {
892 if (!this.isInput(selectedInstanceData.originType)) {
893 // convert Property FE model -> Property BE model, extract only checked
894 selectedComponentInstancesProperties[instanceId] = checkedProperties;
896 selectedComponentInstancesInputs[instanceId] = checkedProperties;
898 } else if (selectedInstanceData instanceof GroupInstance) {
899 selectedGroupInstancesProperties[instanceId] = checkedProperties;
900 } else if (selectedInstanceData instanceof PolicyInstance) {
901 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
904 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
905 propertyNameList.push(property.name);
909 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
911 let modalTitle = 'Declare Properties as List Input';
912 const modal = this.modalService.createCustomModal(new ModalModel(
914 modalTitle, /* title */
919 'blue', /* css class */
920 () => { /* callback */
921 let content:any = modal.instance.dynamicContent.instance;
924 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
925 let typelist: any = PROPERTY_TYPES.LIST;
926 let uniID: any = insId;
927 let boolfalse: any = false;
928 let required: any = content.propertyModel.required;
932 "type": content.propertyModel.simpleType,
936 let schemaProp :any = {
937 "type": content.propertyModel.simpleType,
941 reglistInput.description = content.propertyModel.description;
942 reglistInput.name = content.propertyModel.name;
943 reglistInput.type = typelist;
944 reglistInput.schemaType = content.propertyModel.simpleType;
945 reglistInput.instanceUniqueId = uniID;
946 reglistInput.uniqueId = uniID;
947 reglistInput.required = required;
948 reglistInput.schema = schem;
949 reglistInput.schemaProperty = schemaProp;
952 componentInstInputsMap: content.inputsToCreate,
953 listInput: reglistInput
956 this.topologyTemplateService
957 .createListInput(this.component, input, this.isSelf())
958 .subscribe(response => {
959 this.setInputTabIndication(response.length);
960 this.checkedPropertiesCount = 0;
961 this.checkedChildPropertiesCount = 0;
962 _.forEach(response, (input: InputBEModel) => {
963 let newInput: InputFEModel = new InputFEModel(input);
964 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
965 this.inputs.push(newInput);
966 // create list input does not return updated properties info, so need to reload
967 //this.updatePropertyValueAfterDeclare(newInput);
968 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
969 this.changeSelectedInstance(this.selectedInstanceData);
971 modal.instance.close();
973 }, error => {}); //ignore error
976 /*, getDisabled: function */
978 new ButtonModel('Cancel', 'outline grey', () => {
979 modal.instance.close();
984 // 3rd arg is passed to DeclareListComponent instance
985 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
986 modal.instance.open();
989 /*** DECLARE PROPERTIES/POLICIES ***/
990 declarePropertiesToPolicies = (): void => {
991 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
992 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
994 angular.forEach(instancesIds, (instanceId: string): void => {
995 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
996 if (selectedInstanceData instanceof ComponentInstance) {
997 if (!this.isInput(selectedInstanceData.originType)) {
998 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
1003 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
1004 this.loadingPolicies = true;
1006 this.topologyTemplateService
1007 .createPolicy(this.component, policiesToCreate, this.isSelf())
1008 .subscribe(response => {
1009 this.setPolicyTabIndication(response.length);
1010 this.checkedPropertiesCount = 0;
1011 this.displayPoliciesAsDeclared(response);
1012 this.loadingPolicies = false;
1017 displayPoliciesAsDeclared = (policies) => {
1018 _.forEach(policies, (policy: any) => {
1019 let newPolicy: InputFEModel = new InputFEModel(policy);
1020 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
1021 newPolicy.relatedPropertyName = policy.name;
1022 newPolicy.relatedPropertyValue = policy.value;
1023 this.updatePropertyValueAfterDeclare(newPolicy);
1024 this.policies.push(policy);
1028 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
1029 return new Promise((resolve, reject) => {
1030 if (!this.isValidChangedData) {
1031 reject('Changed data is invalid - cannot save!');
1034 if (!this.changedData.length) {
1039 // make request and its handlers
1041 let handleSuccess, handleError;
1042 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1043 if (this.isPropertiesTabSelected) {
1044 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1045 changedProp = <PropertyFEModel>changedProp;
1046 const propBE = new PropertyBEModel(changedProp);
1047 propBE.toscaPresentation = new ToscaPresentationData();
1048 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1049 propBE.value = changedProp.getJSONValue();
1050 propBE.name = changedProp.origName || changedProp.name;
1051 delete propBE.origName;
1054 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1056 if (this.selectedInstanceData instanceof ComponentInstance) {
1057 if (this.isInput(this.selectedInstanceData.originType)) {
1058 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1059 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1060 request = Observable.forkJoin(
1061 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1062 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1063 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1066 else if (changedInputsProperties.length) {
1067 request = this.componentInstanceServiceNg2
1068 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1070 else if (changedCapabilitiesProperties.length) {
1071 request = this.componentInstanceServiceNg2
1072 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1074 handleSuccess = (response) => {
1075 // reset each changed property with new value and remove it from changed properties list
1076 response.forEach((resInput) => {
1077 const changedProp = <PropertyFEModel>this.changedData.shift();
1078 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1082 if (this.isSelf()) {
1083 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1084 delete cp.constraints;
1088 request = this.componentInstanceServiceNg2
1089 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1091 handleSuccess = (response) => {
1092 // reset each changed property with new value and remove it from changed properties list
1093 response.forEach((resProp) => {
1094 const changedProp = <PropertyFEModel>this.changedData.shift();
1095 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1100 } else if (this.selectedInstanceData instanceof GroupInstance) {
1101 request = this.componentInstanceServiceNg2
1102 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1103 handleSuccess = (response) => {
1104 // reset each changed property with new value and remove it from changed properties list
1105 response.forEach((resProp) => {
1106 const changedProp = <PropertyFEModel>this.changedData.shift();
1107 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1111 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1112 request = this.componentInstanceServiceNg2
1113 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1114 handleSuccess = (response) => {
1115 // reset each changed property with new value and remove it from changed properties list
1116 response.forEach((resProp) => {
1117 const changedProp = <PropertyFEModel>this.changedData.shift();
1118 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1123 } else if (this.isInputsTabSelected) {
1125 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1126 changedInput = <InputFEModel>changedInput;
1127 const inputBE = new InputBEModel(changedInput);
1128 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1131 request = this.componentServiceNg2
1132 .updateComponentInputs(this.component, changedInputs);
1133 handleSuccess = (response) => {
1134 // reset each changed property with new value and remove it from changed properties list
1135 response.forEach((resInput) => {
1136 const changedInput = <InputFEModel>this.changedData.shift();
1137 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1138 changedInput.required = resInput.required;
1139 changedInput.requiredOrig = resInput.required;
1144 this.savingChangedData = true;
1147 this.savingChangedData = false;
1148 if (changedCapabilitiesProperties.length) {
1149 this.reloadInstanceCapabilities();
1151 handleSuccess && handleSuccess(response);
1152 this.updateHasChangedData();
1156 this.savingChangedData = false;
1157 handleError && handleError(error);
1158 this.updateHasChangedData();
1165 reloadInstanceCapabilities = (): void => {
1166 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1167 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1168 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1169 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1170 return instance.capabilities;
1173 }, new CapabilitiesGroup());
1174 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1178 reverseChangedData = ():void => {
1179 // make reverse item handler
1180 let handleReverseItem;
1181 if (this.isPropertiesTabSelected) {
1182 handleReverseItem = (changedItem) => {
1183 changedItem = <PropertyFEModel>changedItem;
1184 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1186 } else if (this.isInputsTabSelected) {
1187 handleReverseItem = (changedItem) => {
1188 changedItem = <InputFEModel>changedItem;
1189 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1190 changedItem.resetMetadata();
1191 changedItem.required = changedItem.requiredOrig;
1195 this.changedData.forEach(handleReverseItem);
1196 this.changedData = [];
1197 this.updateHasChangedData();
1200 updateHasChangedData = ():boolean => {
1201 const curHasChangedData:boolean = (this.changedData.length > 0);
1202 if (curHasChangedData !== this.hasChangedData) {
1203 this.hasChangedData = curHasChangedData;
1204 if(this.hasChangedData) {
1205 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1207 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1210 return this.hasChangedData;
1213 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1214 this.saveChangedData().then(
1216 this.notification.success({
1217 message: 'Successfully saved changes',
1220 if(onSuccessFunction) onSuccessFunction();
1223 this.notification.error({
1224 message: 'Failed to save changes!',
1227 if(onError) onError();
1232 showUnsavedChangesAlert = ():Promise<any> => {
1233 let modalTitle:string;
1234 if (this.isPropertiesTabSelected) {
1235 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1236 } else if (this.isInputsTabSelected) {
1237 modalTitle = `Unsaved inputs for ${this.component.name}`;
1240 return new Promise<any>((resolve, reject) => {
1241 const modal = this.ModalServiceSdcUI.openCustomModal(
1245 type: SdcUiCommon.ModalType.custom,
1246 testId: "navigate-modal",
1249 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1250 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1251 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1252 ] as SdcUiCommon.IModalButtonComponent[]
1253 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1258 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1259 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1260 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1261 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1262 return feProperty.name == input.relatedPropertyName &&
1263 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1265 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1266 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1267 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1268 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1272 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1273 updateCheckedPropertyCount = (increment: boolean): void => {
1274 this.checkedPropertiesCount += (increment) ? 1 : -1;
1275 this.checkedToscaCount = 0;
1276 this.enableToscaFunction = false;
1277 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1280 updateCheckedChildPropertyCount = (increment: boolean): void => {
1281 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1284 togggleToscaBtn = (toscaFlag: boolean) : void => {
1285 this.checkedToscaCount += toscaFlag ? 1 : -1;
1286 if(this.checkedToscaCount == 1){
1287 this.enableToscaFunction = true;
1289 this.enableToscaFunction = false;
1293 setInputTabIndication = (numInputs: number): void => {
1294 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1297 setPolicyTabIndication = (numPolicies: number): void => {
1298 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1301 resetUnsavedChangesForInput = (input:InputFEModel) => {
1302 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1303 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1304 this.updateHasChangedData();
1307 deleteInput = (input: InputFEModel) => {
1308 //reset any unsaved changes to the input before deleting it
1309 this.resetUnsavedChangesForInput(input);
1311 console.debug("==>" + this.constructor.name + ": deleteInput");
1312 let inputToDelete = new InputBEModel(input);
1314 this.componentServiceNg2
1315 .deleteInput(this.component, inputToDelete)
1316 .subscribe(response => {
1317 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1319 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1320 this.changeSelectedInstance(this.selectedInstanceData);
1321 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1323 // if (instanceFeProperties) {
1324 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1325 // return prop.name == input.propertyName;
1328 // if (propToEnable) {
1329 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1330 // propToEnable.setNonDeclared(response.inputPath);
1331 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1332 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1335 }, error => {}); //ignore error
1338 deletePolicy = (policy: PolicyInstance) => {
1339 this.loadingPolicies = true;
1340 this.topologyTemplateService
1341 .deletePolicy(this.component, policy)
1342 .subscribe((response) => {
1343 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1344 this.changeSelectedInstance(this.selectedInstanceData);
1345 this.loadingPolicies = false;
1349 deleteProperty = (property: PropertyFEModel) => {
1350 const propertyToDelete = new PropertyFEModel(property);
1351 this.loadingProperties = true;
1352 const feMap = this.instanceFePropertiesMap;
1353 this.topologyTemplateService
1354 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1355 .subscribe((response) => {
1356 const props = feMap[this.component.uniqueId];
1357 props.splice(props.findIndex(p => p.uniqueId === response),1);
1358 this.loadingProperties = false;
1360 this.loadingProperties = false;
1361 console.error(error);
1365 /*** addProperty ***/
1366 addProperty = (model: string) => {
1367 this.loadDataTypesByComponentModel(model)
1368 let modalTitle = 'Add Property';
1369 let modal = this.modalService.createCustomModal(new ModalModel(
1374 new ButtonModel('Save', 'blue', () => {
1375 modal.instance.dynamicContent.instance.isLoading = true;
1376 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1377 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1378 .subscribe((response) => {
1379 modal.instance.dynamicContent.instance.isLoading = false;
1380 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1381 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1382 modal.instance.close();
1384 modal.instance.dynamicContent.instance.isLoading = false;
1385 this.notification.error({
1386 message: 'Failed to add property:' + error,
1390 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1391 new ButtonModel('Cancel', 'outline grey', () => {
1392 modal.instance.close();
1397 modal.instance.open();
1398 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1403 let modalTitle = 'Add Input';
1404 let modal = this.modalService.createCustomModal(new ModalModel(
1409 new ButtonModel('Save', 'blue', () => {
1410 modal.instance.dynamicContent.instance.isLoading = true;
1411 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1412 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1413 .subscribe((response) => {
1414 modal.instance.dynamicContent.instance.isLoading = false;
1415 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1416 this.inputs.push(newInputProp);
1417 modal.instance.close();
1419 modal.instance.dynamicContent.instance.isLoading = false;
1420 this.notification.error({
1421 message: 'Failed to add input:' + error,
1425 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1426 new ButtonModel('Cancel', 'outline grey', () => {
1427 modal.instance.close();
1432 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1433 modal.instance.open();
1436 /*** SEARCH RELATED FUNCTIONS ***/
1437 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1438 let instanceBePropertiesMap:InstanceBePropertiesMap;
1439 this.componentServiceNg2
1440 .filterComponentInstanceProperties(this.component, filterData)
1441 .subscribe((response) => {
1442 this.processInstancePropertiesResponse(response, false);
1443 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1444 this.searchPropertyName = filterData.propertyName;//mark in table
1445 this.hierarchyNavTabs.triggerTabChange('Composition');
1446 this.propertiesNavigationData = [];
1447 this.displayClearSearch = true;
1448 }, (error) => {}); //ignore error
1452 clearSearch = () => {
1453 this.instancesNavigationData = this.instances;
1454 this.searchPropertyName = "";
1455 this.hierarchyPropertiesDisplayOptions.searchText = "";
1456 this.displayClearSearch = false;
1457 this.advanceSearch.clearAll();
1458 this.searchQuery = '';
1461 clickOnClearSearch = () => {
1463 this.selectFirstInstanceByDefault();
1464 this.hierarchyNavTabs.triggerTabChange('Composition');
1467 private isInput = (instanceType:string):boolean =>{
1468 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1471 loadDataTypesByComponentModel(model:string) {
1472 this.propertyCreatorComponent.filterDataTypesByModel(model);