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";
75 const SERVICE_SELF_TITLE = "SELF";
77 templateUrl: './properties-assignment.page.component.html',
78 styleUrls: ['./properties-assignment.page.component.less']
80 export class PropertiesAssignmentComponent {
81 title = "Properties & Inputs";
83 component: ComponentData;
84 componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
85 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
87 propertiesNavigationData = [];
88 instancesNavigationData = [];
90 instanceFePropertiesMap: InstanceFePropertiesMap;
91 inputs: Array<InputFEModel> = [];
92 policies: Array<PolicyInstance> = [];
93 instances: Array<ComponentInstance | GroupInstance | PolicyInstance> = [];
95 propertyStructureHeader: string;
97 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
98 selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = null;
99 checkedPropertiesCount: number = 0;
100 checkedChildPropertiesCount: number = 0;
101 enableToscaFunction: boolean = false;
102 checkedToscaCount: number = 0;
104 hierarchyPropertiesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
105 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
106 displayClearSearch = false;
107 searchPropertyName: string;
109 isInputsTabSelected: boolean;
110 isPropertiesTabSelected: boolean;
111 isPoliciesTabSelected: boolean;
113 resourceIsReadonly: boolean;
114 loadingInstances: boolean = false;
115 loadingInputs: boolean = false;
116 loadingPolicies: boolean = false;
117 loadingProperties: boolean = false;
118 changedData: Array<PropertyFEModel | InputFEModel>;
119 hasChangedData: boolean;
120 isValidChangedData: boolean;
121 savingChangedData: boolean;
122 stateChangeStartUnregister: Function;
123 serviceBePropertiesMap: InstanceBePropertiesMap;
124 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
125 selectedInstance_FlattenCapabilitiesList: Capability[];
126 componentInstancePropertyMap : PropertiesGroup;
127 defaultInputName: string;
129 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
130 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
131 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
133 constructor(private propertiesService: PropertiesService,
134 private hierarchyNavService: HierarchyNavService,
135 private propertiesUtils: PropertiesUtils,
136 private inputsUtils: InputsUtils,
137 private componentServiceNg2: ComponentServiceNg2,
138 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
139 private propertyCreatorComponent: PropertyCreatorComponent,
140 @Inject("$stateParams") _stateParams,
141 @Inject("$scope") private $scope: ng.IScope,
142 @Inject("$state") private $state: ng.ui.IStateService,
143 @Inject("Notification") private notification: any,
144 private componentModeService: ComponentModeService,
145 private eventListenerService: EventListenerService,
146 private ModalServiceSdcUI: SdcUiServices.ModalService,
147 private modalService: ModalService,
148 private keysPipe: KeysPipe,
149 private topologyTemplateService: TopologyTemplateService,
150 private translateService: TranslateService) {
152 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
153 /* 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
154 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
155 this.component = _stateParams.component;
156 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
157 this.updateViewMode();
158 this.changedData = [];
159 this.updateHasChangedData();
160 this.isValidChangedData = true;
164 console.debug("==>" + this.constructor.name + ": ngOnInit");
165 this.loadingInputs = true;
166 this.loadingPolicies = true;
167 this.loadingInstances = true;
168 this.loadingProperties = true;
169 this.topologyTemplateService
170 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
171 .subscribe(response => {
172 _.forEach(response.inputs, (input: InputBEModel) => {
173 const newInput: InputFEModel = new InputFEModel(input);
174 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
175 this.inputs.push(newInput); //only push items that were declared via SDC
177 this.componentInstancePropertyMap = response.componentInstancesProperties;
178 this.loadingInputs = false;
182 this.componentServiceNg2
183 .getComponentResourcePropertiesData(this.component)
184 .subscribe(response => {
185 this.loadingPolicies = false;
187 this.instances.push(...response.componentInstances);
188 this.instances.push(...response.groupInstances);
189 this.instances.push(...response.policies);
191 if (response.componentInstances) {
192 response.componentInstances.forEach(instance => {
193 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
195 iconClass: instance.iconClass,
196 originArchived: instance.originArchived
201 _.forEach(response.policies, (policy: any) => {
202 const newPolicy: InputFEModel = new InputFEModel(policy);
203 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
204 this.policies.push(policy);
207 // add the service self instance to the top of the list.
208 const serviceInstance = new ComponentInstance();
209 serviceInstance.name = SERVICE_SELF_TITLE;
210 serviceInstance.uniqueId = this.component.uniqueId;
211 this.instances.unshift(serviceInstance);
213 _.forEach(this.instances, (instance) => {
214 this.instancesNavigationData.push(instance);
215 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
217 iconClass: instance.iconClass,
218 originArchived: instance.originArchived
221 this.loadingInstances = false;
222 if (this.instancesNavigationData[0] == undefined) {
223 this.loadingProperties = false;
225 this.selectFirstInstanceByDefault();
227 this.loadingInstances = false;
230 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
231 // stop if has changed properties
232 if (this.hasChangedData) {
233 event.preventDefault();
234 this.showUnsavedChangesAlert().then(() => {
235 this.$state.go(toState, toParams);
241 this.loadDataTypesByComponentModel(this.component.model);
245 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
246 this.stateChangeStartUnregister();
249 selectFirstInstanceByDefault = () => {
250 if (this.instancesNavigationData[0] !== undefined) {
251 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
255 updateViewMode = () => {
256 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
259 onCheckout = (component: ComponentData) => {
260 this.component = component;
261 this.updateViewMode();
264 isSelf = (): boolean => {
265 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
268 showAddProperties = (): boolean => {
269 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
272 return this.isSelf();
275 getServiceProperties() {
276 this.loadingProperties = true;
277 this.topologyTemplateService
278 .getServiceProperties(this.component.uniqueId)
279 .subscribe((response) => {
280 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
281 this.serviceBePropertiesMap[this.component.uniqueId] = response;
282 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
283 this.loadingProperties = false;
285 this.loadingProperties = false;
289 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
290 // stop if has changed properties
291 if (this.hasChangedData) {
292 this.showUnsavedChangesAlert().then((resolve) => {
293 this.changeSelectedInstance(instance)
298 this.changeSelectedInstance(instance);
301 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
302 this.selectedInstanceData = instance;
303 this.loadingProperties = true;
304 if (instance instanceof ComponentInstance) {
305 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
306 if (this.isInput(instance.originType)) {
307 this.componentInstanceServiceNg2
308 .getComponentInstanceInputs(this.component, instance)
309 .subscribe(response => {
310 instanceBePropertiesMap[instance.uniqueId] = response;
311 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
315 this.loadingProperties = false;
317 } else if (this.isSelf()) {
318 this.getServiceProperties();
320 this.componentInstanceServiceNg2
321 .getComponentInstanceProperties(this.component, instance.uniqueId)
322 .subscribe(response => {
323 instanceBePropertiesMap[instance.uniqueId] = response;
324 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
328 this.loadingProperties = false;
331 this.loadingProperties = false;
332 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
333 } else if (instance instanceof GroupInstance) {
334 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
335 this.componentInstanceServiceNg2
336 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
337 .subscribe((response) => {
338 instanceBePropertiesMap[instance.uniqueId] = response;
339 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
343 this.loadingProperties = false;
345 } else if (instance instanceof PolicyInstance) {
346 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
347 this.componentInstanceServiceNg2
348 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
349 .subscribe((response) => {
350 instanceBePropertiesMap[instance.uniqueId] = response;
351 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
355 this.loadingProperties = false;
358 this.loadingProperties = false;
361 if (this.searchPropertyName) {
364 //clear selected property from the navigation
365 this.selectedFlatProperty = new SimpleFlatProperty();
366 this.propertiesNavigationData = [];
367 this.checkedToscaCount = 0;
368 this.enableToscaFunction = false;
372 * Entry point handling response from server
374 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
375 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
376 this.checkedPropertiesCount = 0;
377 this.checkedChildPropertiesCount = 0;
380 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
381 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
382 let currentUniqueId = this.selectedInstanceData.uniqueId;
383 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
384 let isCapabilityOwnedByInstance: boolean;
385 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
386 this.selectedInstance_FlattenCapabilitiesList,
387 (result, cap: Capability) => {
388 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
389 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
390 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
391 if (cap.properties && isCapabilityOwnedByInstance) {
392 _.forEach(cap.properties, prop => {
393 if (!prop.origName) {
394 prop.origName = prop.name;
395 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
398 return result.concat(cap.properties);
402 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
403 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
404 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
405 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
407 //concatenate capabilitiesProps to all props list
408 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
409 this.checkedPropertiesCount = 0;
412 isCapabilityProperty = (prop: PropertyBEModel) => {
413 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
416 /*** VALUE CHANGE EVENTS ***/
417 dataChanged = (item: PropertyFEModel | InputFEModel) => {
419 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
420 itemHasChanged = item.hasValueObjChanged();
421 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
422 itemHasChanged = item.hasChanged();
423 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
424 itemHasChanged = item.hasDefaultValueChanged();
427 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
428 if (itemHasChanged) {
429 if (dataChangedIdx === -1) {
430 this.changedData.push(item);
433 if (dataChangedIdx !== -1) {
434 this.changedData.splice(dataChangedIdx, 1);
438 if (this.isPropertiesTabSelected) {
439 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
440 } else if (this.isInputsTabSelected) {
441 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
442 } else if (this.isPoliciesTabSelected) {
443 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
445 this.updateHasChangedData();
449 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
452 * Handle select node in navigation area, and select the row in table
454 onPropertySelectedUpdate = ($event) => {
455 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
456 this.selectedFlatProperty = $event;
457 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
458 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
462 * When user select row in table, this will prepare the hirarchy object for the tree.
464 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
465 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
466 let property = propertyRowSelectedEvent.propertyModel;
467 let instanceName = propertyRowSelectedEvent.instanceName;
468 this.propertyStructureHeader = null;
470 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
471 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
472 let simpleFlatProperty: Array<SimpleFlatProperty>;
473 if (property instanceof PropertyFEModel) {
474 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
475 } else if (property instanceof DerivedFEProperty) {
476 // Need to find parent PropertyFEModel
477 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
478 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
480 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
482 this.propertiesNavigationData = simpleFlatProperty;
485 // Update the header in the navigation tree with property name.
486 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
488 // Set selected property in table
489 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
490 this.hierarchyNavTabs.triggerTabChange('Property Structure');
494 selectInstanceRow = ($event) => {//get instance name
495 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
496 return instance.name == $event;
498 this.hierarchyNavTabs.triggerTabChange('Composition');
501 tabChanged = (event) => {
502 // stop if has changed properties
503 if (this.hasChangedData) {
504 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
505 this.showUnsavedChangesAlert().then((proceed) => {
506 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
512 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
513 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
514 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
515 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
516 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
517 this.propertyStructureHeader = null;
518 this.searchQuery = '';
522 * Select Tosca function value from defined values
524 selectToscaFunctionAndValues = (): void => {
525 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
526 if (!selectedInstanceData) {
529 this.openToscaGetFunctionModal();
532 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
533 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
534 const instanceId: string = instancesIds[0];
535 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
536 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
539 private buildCheckedInstanceProperty(): PropertyBEModel {
540 return this.buildCheckedInstanceProperties()[0];
543 private buildCheckedInstanceProperties(): PropertyBEModel[] {
544 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
545 const instanceId: string = instancesIds[0];
546 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
549 private openToscaGetFunctionModal() {
550 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
551 const modalButtons = [];
552 let disableSaveButtonFlag = true;
553 const modal = this.modalService.createCustomModal(new ModalModel(
560 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
562 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
563 if (toscaGetFunction) {
564 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
566 this.clearCheckedInstancePropertyValue();
568 this.modalService.closeCurrentModal();
570 (): boolean => { return disableSaveButtonFlag }
572 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
573 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
574 this.modalService.closeCurrentModal();
578 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
579 'property': checkedInstanceProperty,
580 'componentInstanceMap': this.componentInstanceMap
582 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
583 disableSaveButtonFlag = !validationEvent.isValid;
585 modal.instance.open();
588 private clearCheckedInstancePropertyValue() {
589 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
590 const currentValue : any = checkedInstanceProperty.value;
591 checkedInstanceProperty.getInputValues = null;
592 checkedInstanceProperty.value = null;
593 checkedInstanceProperty.toscaFunction = null;
594 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
595 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
596 const parts = propertiesNameArray.split("#");
598 if (this.isListOrMap(checkedInstanceProperty.type)) {
599 if (checkedInstanceProperty.schemaType == PROPERTY_TYPES.MAP) {
600 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).parentMapKey);
602 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).mapKey);
603 if (checkedInstanceProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedInstanceProperty.schemaType)) {
604 currentKey.push(parts.reverse()[0]);
607 if (propertiesNameArray.length > 1){
608 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
609 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
611 if(currentValue !== null && currentKey.length > 0){
612 let valueJson = JSON.parse(currentValue);
613 if(currentKey.length >1){
614 let innerObj = valueJson[currentKey[0]];
615 delete innerObj[currentKey[1]];
616 valueJson[currentKey[0]] = innerObj;
618 delete valueJson[currentKey[0]];
620 if (checkedInstanceProperty.type == PROPERTY_TYPES.LIST && currentKey.length == 1) {
621 let listValue = valueJson.filter(function (item) {
622 return item != null && item != '';
624 checkedInstanceProperty.value = JSON.stringify(listValue);
626 checkedInstanceProperty.value = JSON.stringify(valueJson);
630 if (this.selectedInstanceData instanceof ComponentInstance) {
631 var toRemove = this.changedData.filter(obj => {
632 return obj.name == checkedInstanceProperty.name && obj.type == checkedInstanceProperty.type && obj.value == null;
634 const index: number = this.changedData.indexOf(toRemove[0]);
636 this.changedData.splice(index, 1);
638 this.updateInstanceProperty(checkedInstanceProperty);
639 } else if (this.selectedInstanceData instanceof GroupInstance) {
640 this.updateGroupInstanceProperty(checkedInstanceProperty);
641 } else if (this.selectedInstanceData instanceof PolicyInstance) {
642 this.updatePolicyInstanceProperty(checkedInstanceProperty);
646 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
647 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
648 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
649 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
650 const parts = propertiesName.split("#");
652 if (this.isListOrMap(checkedProperty.type)) {
653 if (checkedProperty.schemaType == PROPERTY_TYPES.MAP) {
654 currentKey.push((<DerivedFEProperty>checkedProperty.input).parentMapKey);
656 currentKey.push((<DerivedFEProperty>checkedProperty.input).mapKey);
657 if (checkedProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedProperty.schemaType)) {
658 currentKey.push(parts.reverse()[0]);
661 if (checkedProperty.subPropertyToscaFunctions == null){
662 checkedProperty.subPropertyToscaFunctions = [];
664 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
665 if (!subPropertyToscaFunction){
666 subPropertyToscaFunction = new SubPropertyToscaFunction();
667 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
669 subPropertyToscaFunction.toscaFunction = toscaFunction;
670 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
673 checkedProperty.subPropertyToscaFunctions = null;
674 checkedProperty.toscaFunction = toscaFunction;
676 if (this.selectedInstanceData instanceof ComponentInstance) {
677 this.updateInstanceProperty(checkedProperty);
678 } else if (this.selectedInstanceData instanceof GroupInstance) {
679 this.updateGroupInstanceProperty(checkedProperty);
680 } else if (this.selectedInstanceData instanceof PolicyInstance) {
681 this.updatePolicyInstanceProperty(checkedProperty);
685 private isComplexSchemaType(propertyType: string): boolean {
686 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
689 private isListOrMap(propertyType: string): boolean {
690 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
693 private areEqual(array1: string[], array2: string[]): boolean {
694 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
697 updateInstanceProperty(instanceProperty: PropertyBEModel) {
698 this.loadingProperties = true;
699 this.enableToscaFunction = false;
700 this.checkedToscaCount = 0;
702 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
703 this.selectedInstanceData.uniqueId, [instanceProperty])
705 this.changeSelectedInstance(this.getSelectedInstance());
707 this.loadingProperties = false;
708 console.error(error);
710 this.loadingProperties = false;
714 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
715 this.loadingProperties = true;
716 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
717 this.selectedInstanceData.uniqueId, [instanceProperty])
719 this.changeSelectedInstance(this.getSelectedInstance());
721 this.loadingProperties = false;
722 console.error(error);
724 this.loadingProperties = false;
728 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
729 this.loadingProperties = true;
730 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
731 this.selectedInstanceData.uniqueId, [instanceProperty])
733 this.changeSelectedInstance(this.getSelectedInstance());
735 this.loadingProperties = false;
736 console.error(error);
738 this.loadingProperties = false;
742 declareInput = (): void => {
743 if (this.checkedPropertiesCount == 1) {
744 this.openAddInputNameAndDeclareInputModal();
745 } else if (this.checkedPropertiesCount > 1) {
746 this.declareInputFromProperties();
750 /*** DECLARE PROPERTIES/INPUTS ***/
751 declareInputFromProperties = (inputName?: string): void => {
752 console.debug("==>" + this.constructor.name + ": declareProperties");
754 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
755 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
756 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
757 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
758 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
760 angular.forEach(instancesIds, (instanceId: string): void => {
761 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
762 if (selectedInstanceData instanceof ComponentInstance) {
763 if (!this.isInput(selectedInstanceData.originType)) {
764 // convert Property FE model -> Property BE model, extract only checked
765 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
767 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
770 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
772 } else if (selectedInstanceData instanceof GroupInstance) {
773 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
774 } else if (selectedInstanceData instanceof PolicyInstance) {
775 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
779 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
781 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
782 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
783 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
785 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
786 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
789 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
790 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
791 prop => !this.isCapabilityProperty(prop)
793 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
794 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
797 let isCapabilityPropertyChanged = false;
799 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
800 (prop: PropertyBEModel) => {
801 prop.name = prop.origName || prop.name;
802 if (this.isCapabilityProperty(prop)) {
803 isCapabilityPropertyChanged = true;
807 this.topologyTemplateService
808 .createInput(this.component, inputsToCreate, this.isSelf())
809 .subscribe((response) => {
810 this.selectInstanceRow(SERVICE_SELF_TITLE);
811 this.onInstanceSelectedUpdate(this.instances[0]);
812 this.setInputTabIndication(response.length);
813 this.checkedPropertiesCount = 0;
814 this.checkedChildPropertiesCount = 0;
815 _.forEach(response, (input: InputBEModel) => {
816 const newInput: InputFEModel = new InputFEModel(input);
817 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
818 this.inputs.push(newInput);
819 this.updatePropertyValueAfterDeclare(newInput);
821 if (isCapabilityPropertyChanged) {
822 this.reloadInstanceCapabilities();
824 }, error => {}); //ignore error
827 generateDefaultInputName = (): string => {
828 let defaultInputName: string;
829 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
830 angular.forEach(instancesIds, (instanceId: string) => {
831 let selectedProperty: PropertyBEModel = new PropertyBEModel(this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId])[0]);
832 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
833 defaultInputName = this.generateInputName(selectedInstanceData.invariantName, selectedProperty.name);
835 return defaultInputName;
838 private generateInputName = (componentName: string, propertyName: string): string => {
839 let inputName: string;
841 if (propertyName.includes("::")) {
842 propertyName = propertyName.replace(/::/g, "_");
845 inputName = componentName + "_" + propertyName;
847 inputName = propertyName;
853 private openAddInputNameAndDeclareInputModal = (): void => {
854 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
855 const modalButtons = [];
856 const modal = this.modalService.createCustomModal(new ModalModel(
863 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
865 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
867 this.declareInputFromProperties(inputName);
869 this.notification.warning({
870 message: 'Failed to set input name',
874 this.modalService.closeCurrentModal();
877 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
878 this.modalService.closeCurrentModal();
880 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultInputName()});
881 modal.instance.open();
884 declareListProperties = (): void => {
885 // get selected properties
886 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
887 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
888 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
889 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
890 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
891 let propertyNameList: Array<string> = [];
894 angular.forEach(instancesIds, (instanceId: string): void => {
896 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
897 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
899 if (selectedInstanceData instanceof ComponentInstance) {
900 if (!this.isInput(selectedInstanceData.originType)) {
901 // convert Property FE model -> Property BE model, extract only checked
902 selectedComponentInstancesProperties[instanceId] = checkedProperties;
904 selectedComponentInstancesInputs[instanceId] = checkedProperties;
906 } else if (selectedInstanceData instanceof GroupInstance) {
907 selectedGroupInstancesProperties[instanceId] = checkedProperties;
908 } else if (selectedInstanceData instanceof PolicyInstance) {
909 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
912 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
913 propertyNameList.push(property.name);
917 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
919 let modalTitle = 'Declare Properties as List Input';
920 const modal = this.modalService.createCustomModal(new ModalModel(
922 modalTitle, /* title */
927 'blue', /* css class */
928 () => { /* callback */
929 let content:any = modal.instance.dynamicContent.instance;
932 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
933 let typelist: any = PROPERTY_TYPES.LIST;
934 let uniID: any = insId;
935 let boolfalse: any = false;
936 let required: any = content.propertyModel.required;
940 "type": content.propertyModel.simpleType,
944 let schemaProp :any = {
945 "type": content.propertyModel.simpleType,
949 reglistInput.description = content.propertyModel.description;
950 reglistInput.name = content.propertyModel.name;
951 reglistInput.type = typelist;
952 reglistInput.schemaType = content.propertyModel.simpleType;
953 reglistInput.instanceUniqueId = uniID;
954 reglistInput.uniqueId = uniID;
955 reglistInput.required = required;
956 reglistInput.schema = schem;
957 reglistInput.schemaProperty = schemaProp;
960 componentInstInputsMap: content.inputsToCreate,
961 listInput: reglistInput
964 this.topologyTemplateService
965 .createListInput(this.component, input, this.isSelf())
966 .subscribe(response => {
967 this.setInputTabIndication(response.length);
968 this.checkedPropertiesCount = 0;
969 this.checkedChildPropertiesCount = 0;
970 _.forEach(response, (input: InputBEModel) => {
971 let newInput: InputFEModel = new InputFEModel(input);
972 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
973 this.inputs.push(newInput);
974 // create list input does not return updated properties info, so need to reload
975 //this.updatePropertyValueAfterDeclare(newInput);
976 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
977 this.changeSelectedInstance(this.selectedInstanceData);
979 modal.instance.close();
981 }, error => {}); //ignore error
984 /*, getDisabled: function */
986 new ButtonModel('Cancel', 'outline grey', () => {
987 modal.instance.close();
992 // 3rd arg is passed to DeclareListComponent instance
993 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
994 modal.instance.open();
997 /*** DECLARE PROPERTIES/POLICIES ***/
998 declarePropertiesToPolicies = (): void => {
999 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
1000 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
1002 angular.forEach(instancesIds, (instanceId: string): void => {
1003 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
1004 if (selectedInstanceData instanceof ComponentInstance) {
1005 if (!this.isInput(selectedInstanceData.originType)) {
1006 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
1011 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
1012 this.loadingPolicies = true;
1014 this.topologyTemplateService
1015 .createPolicy(this.component, policiesToCreate, this.isSelf())
1016 .subscribe(response => {
1017 this.setPolicyTabIndication(response.length);
1018 this.checkedPropertiesCount = 0;
1019 this.displayPoliciesAsDeclared(response);
1020 this.loadingPolicies = false;
1025 displayPoliciesAsDeclared = (policies) => {
1026 _.forEach(policies, (policy: any) => {
1027 let newPolicy: InputFEModel = new InputFEModel(policy);
1028 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
1029 newPolicy.relatedPropertyName = policy.name;
1030 newPolicy.relatedPropertyValue = policy.value;
1031 this.updatePropertyValueAfterDeclare(newPolicy);
1032 this.policies.push(policy);
1036 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
1037 return new Promise((resolve, reject) => {
1038 if (!this.isValidChangedData) {
1039 reject('Changed data is invalid - cannot save!');
1042 if (!this.changedData.length) {
1047 // make request and its handlers
1049 let handleSuccess, handleError;
1050 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1051 if (this.isPropertiesTabSelected) {
1052 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1053 changedProp = <PropertyFEModel>changedProp;
1054 const propBE = new PropertyBEModel(changedProp);
1055 propBE.toscaPresentation = new ToscaPresentationData();
1056 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1057 propBE.value = changedProp.getJSONValue();
1058 propBE.name = changedProp.origName || changedProp.name;
1059 delete propBE.origName;
1062 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1064 if (this.selectedInstanceData instanceof ComponentInstance) {
1065 if (this.isInput(this.selectedInstanceData.originType)) {
1066 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1067 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1068 request = Observable.forkJoin(
1069 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1070 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1071 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1074 else if (changedInputsProperties.length) {
1075 request = this.componentInstanceServiceNg2
1076 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1078 else if (changedCapabilitiesProperties.length) {
1079 request = this.componentInstanceServiceNg2
1080 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1082 handleSuccess = (response) => {
1083 // reset each changed property with new value and remove it from changed properties list
1084 response.forEach((resInput) => {
1085 const changedProp = <PropertyFEModel>this.changedData.shift();
1086 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1090 if (this.isSelf()) {
1091 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1092 delete cp.constraints;
1096 request = this.componentInstanceServiceNg2
1097 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1099 handleSuccess = (response) => {
1100 // reset each changed property with new value and remove it from changed properties list
1101 response.forEach((resProp) => {
1102 const changedProp = <PropertyFEModel>this.changedData.shift();
1103 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1108 } else if (this.selectedInstanceData instanceof GroupInstance) {
1109 request = this.componentInstanceServiceNg2
1110 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1111 handleSuccess = (response) => {
1112 // reset each changed property with new value and remove it from changed properties list
1113 response.forEach((resProp) => {
1114 const changedProp = <PropertyFEModel>this.changedData.shift();
1115 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1119 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1120 request = this.componentInstanceServiceNg2
1121 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1122 handleSuccess = (response) => {
1123 // reset each changed property with new value and remove it from changed properties list
1124 response.forEach((resProp) => {
1125 const changedProp = <PropertyFEModel>this.changedData.shift();
1126 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1131 } else if (this.isInputsTabSelected) {
1133 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1134 changedInput = <InputFEModel>changedInput;
1135 const inputBE = new InputBEModel(changedInput);
1136 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1139 request = this.componentServiceNg2
1140 .updateComponentInputs(this.component, changedInputs);
1141 handleSuccess = (response) => {
1142 // reset each changed property with new value and remove it from changed properties list
1143 response.forEach((resInput) => {
1144 const changedInput = <InputFEModel>this.changedData.shift();
1145 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1146 changedInput.required = resInput.required;
1147 changedInput.requiredOrig = resInput.required;
1152 this.savingChangedData = true;
1155 this.savingChangedData = false;
1156 if (changedCapabilitiesProperties.length) {
1157 this.reloadInstanceCapabilities();
1159 handleSuccess && handleSuccess(response);
1160 this.updateHasChangedData();
1164 this.savingChangedData = false;
1165 handleError && handleError(error);
1166 this.updateHasChangedData();
1173 reloadInstanceCapabilities = (): void => {
1174 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1175 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1176 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1177 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1178 return instance.capabilities;
1181 }, new CapabilitiesGroup());
1182 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1186 reverseChangedData = ():void => {
1187 // make reverse item handler
1188 let handleReverseItem;
1189 if (this.isPropertiesTabSelected) {
1190 handleReverseItem = (changedItem) => {
1191 changedItem = <PropertyFEModel>changedItem;
1192 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1194 } else if (this.isInputsTabSelected) {
1195 handleReverseItem = (changedItem) => {
1196 changedItem = <InputFEModel>changedItem;
1197 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1198 changedItem.resetMetadata();
1199 changedItem.required = changedItem.requiredOrig;
1203 this.changedData.forEach(handleReverseItem);
1204 this.changedData = [];
1205 this.updateHasChangedData();
1208 updateHasChangedData = ():boolean => {
1209 const curHasChangedData:boolean = (this.changedData.length > 0);
1210 if (curHasChangedData !== this.hasChangedData) {
1211 this.hasChangedData = curHasChangedData;
1212 if(this.hasChangedData) {
1213 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1215 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1218 return this.hasChangedData;
1221 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1222 this.saveChangedData().then(
1224 this.notification.success({
1225 message: 'Successfully saved changes',
1228 if(onSuccessFunction) onSuccessFunction();
1231 this.notification.error({
1232 message: 'Failed to save changes!',
1235 if(onError) onError();
1240 showUnsavedChangesAlert = ():Promise<any> => {
1241 let modalTitle:string;
1242 if (this.isPropertiesTabSelected) {
1243 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1244 } else if (this.isInputsTabSelected) {
1245 modalTitle = `Unsaved inputs for ${this.component.name}`;
1248 return new Promise<any>((resolve, reject) => {
1249 const modal = this.ModalServiceSdcUI.openCustomModal(
1253 type: SdcUiCommon.ModalType.custom,
1254 testId: "navigate-modal",
1257 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1258 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1259 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1260 ] as SdcUiCommon.IModalButtonComponent[]
1261 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1266 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1267 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1268 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1269 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1270 return feProperty.name == input.relatedPropertyName &&
1271 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1273 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1274 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1275 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1276 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1280 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1281 updateCheckedPropertyCount = (increment: boolean): void => {
1282 this.checkedPropertiesCount += (increment) ? 1 : -1;
1283 this.checkedToscaCount = 0;
1284 this.enableToscaFunction = false;
1285 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1288 updateCheckedChildPropertyCount = (increment: boolean): void => {
1289 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1292 togggleToscaBtn = (toscaFlag: boolean) : void => {
1293 this.checkedToscaCount += toscaFlag ? 1 : -1;
1294 if(this.checkedToscaCount == 1){
1295 this.enableToscaFunction = true;
1297 this.enableToscaFunction = false;
1301 setInputTabIndication = (numInputs: number): void => {
1302 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1305 setPolicyTabIndication = (numPolicies: number): void => {
1306 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1309 resetUnsavedChangesForInput = (input:InputFEModel) => {
1310 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1311 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1312 this.updateHasChangedData();
1315 deleteInput = (input: InputFEModel) => {
1316 //reset any unsaved changes to the input before deleting it
1317 this.resetUnsavedChangesForInput(input);
1319 console.debug("==>" + this.constructor.name + ": deleteInput");
1320 let inputToDelete = new InputBEModel(input);
1322 this.componentServiceNg2
1323 .deleteInput(this.component, inputToDelete)
1324 .subscribe(response => {
1325 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1327 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1328 this.changeSelectedInstance(this.selectedInstanceData);
1329 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1331 // if (instanceFeProperties) {
1332 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1333 // return prop.name == input.propertyName;
1336 // if (propToEnable) {
1337 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1338 // propToEnable.setNonDeclared(response.inputPath);
1339 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1340 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1343 }, error => {}); //ignore error
1346 deletePolicy = (policy: PolicyInstance) => {
1347 this.loadingPolicies = true;
1348 this.topologyTemplateService
1349 .deletePolicy(this.component, policy)
1350 .subscribe((response) => {
1351 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1352 this.changeSelectedInstance(this.selectedInstanceData);
1353 this.loadingPolicies = false;
1357 deleteProperty = (property: PropertyFEModel) => {
1358 const propertyToDelete = new PropertyFEModel(property);
1359 this.loadingProperties = true;
1360 const feMap = this.instanceFePropertiesMap;
1361 this.topologyTemplateService
1362 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1363 .subscribe((response) => {
1364 const props = feMap[this.component.uniqueId];
1365 props.splice(props.findIndex(p => p.uniqueId === response),1);
1366 this.loadingProperties = false;
1368 this.loadingProperties = false;
1369 console.error(error);
1373 /*** addProperty ***/
1374 addProperty = (model: string) => {
1375 this.loadDataTypesByComponentModel(model)
1376 let modalTitle = 'Add Property';
1377 let modal = this.modalService.createCustomModal(new ModalModel(
1382 new ButtonModel('Save', 'blue', () => {
1383 modal.instance.dynamicContent.instance.isLoading = true;
1384 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1385 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1386 .subscribe((response) => {
1387 modal.instance.dynamicContent.instance.isLoading = false;
1388 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1389 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1390 modal.instance.close();
1392 modal.instance.dynamicContent.instance.isLoading = false;
1393 this.notification.error({
1394 message: 'Failed to add property:' + error,
1398 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1399 new ButtonModel('Cancel', 'outline grey', () => {
1400 modal.instance.close();
1405 modal.instance.open();
1406 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1411 let modalTitle = 'Add Input';
1412 let modal = this.modalService.createCustomModal(new ModalModel(
1417 new ButtonModel('Save', 'blue', () => {
1418 modal.instance.dynamicContent.instance.isLoading = true;
1419 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1420 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1421 .subscribe((response) => {
1422 modal.instance.dynamicContent.instance.isLoading = false;
1423 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1424 this.inputs.push(newInputProp);
1425 modal.instance.close();
1427 modal.instance.dynamicContent.instance.isLoading = false;
1428 this.notification.error({
1429 message: 'Failed to add input:' + error,
1433 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1434 new ButtonModel('Cancel', 'outline grey', () => {
1435 modal.instance.close();
1440 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1441 modal.instance.open();
1444 /*** SEARCH RELATED FUNCTIONS ***/
1445 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1446 let instanceBePropertiesMap:InstanceBePropertiesMap;
1447 this.componentServiceNg2
1448 .filterComponentInstanceProperties(this.component, filterData)
1449 .subscribe((response) => {
1450 this.processInstancePropertiesResponse(response, false);
1451 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1452 this.searchPropertyName = filterData.propertyName;//mark in table
1453 this.hierarchyNavTabs.triggerTabChange('Composition');
1454 this.propertiesNavigationData = [];
1455 this.displayClearSearch = true;
1456 }, (error) => {}); //ignore error
1460 clearSearch = () => {
1461 this.instancesNavigationData = this.instances;
1462 this.searchPropertyName = "";
1463 this.hierarchyPropertiesDisplayOptions.searchText = "";
1464 this.displayClearSearch = false;
1465 this.advanceSearch.clearAll();
1466 this.searchQuery = '';
1469 clickOnClearSearch = () => {
1471 this.selectFirstInstanceByDefault();
1472 this.hierarchyNavTabs.triggerTabChange('Composition');
1475 private isInput = (instanceType:string):boolean =>{
1476 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1479 loadDataTypesByComponentModel(model:string) {
1480 this.propertyCreatorComponent.filterDataTypesByModel(model);