2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import * as _ from "lodash";
22 import {Component, Inject, ViewChild} from "@angular/core";
23 import {PropertiesService} from "../../services/properties.service";
26 Component as ComponentData,
29 FilterPropertiesAssignmentData,
33 InstanceBePropertiesMap,
34 InstanceFePropertiesMap,
35 InstancePropertiesAPIMap,
42 PropertyDeclareAPIModel,
45 import {ResourceType} from "app/utils";
46 import {ComponentServiceNg2} from "../../services/component-services/component.service";
47 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
48 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
49 import {KeysPipe} from 'app/ng2/pipes/keys.pipe';
50 import {EVENTS, PROPERTY_TYPES, WorkspaceMode, PROPERTY_DATA} from "../../../utils/constants";
51 import {EventListenerService} from "app/services/event-listener-service"
52 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
53 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
54 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
55 import {HierarchyNavService} from "./services/hierarchy-nav.service";
56 import {PropertiesUtils} from "./services/properties.utils";
57 import {ComponentModeService} from "../../services/component-services/component-mode.service";
58 import {Tab, Tabs} from "../../components/ui/tabs/tabs.component";
59 import {InputsUtils} from "./services/inputs.utils";
60 import {InstanceFeDetails} from "../../../models/instance-fe-details";
61 import {SdcUiCommon, SdcUiServices} from "onap-ui-angular";
62 import {UnsavedChangesComponent} from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
63 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
64 import {ModalService} from "../../services/modal.service";
65 import {DeclareListComponent} from "./declare-list/declare-list.component";
66 import {ToscaFunctionComponent, ToscaFunctionValidationEvent} from "./tosca-function/tosca-function.component";
67 import {CapabilitiesGroup, Capability} from "../../../models/capability";
68 import {ToscaPresentationData} from "../../../models/tosca-presentation";
69 import {Observable} from "rxjs";
70 import {TranslateService} from "../../shared/translator/translate.service";
71 import {ToscaFunction} from "../../../models/tosca-function";
72 import {SubPropertyToscaFunction} from "../../../models/sub-property-tosca-function";
73 import {DeclareInputComponent} from "./declare-input/declare-input.component";
74 import {ElementService} from "../../services/element.service";
75 import {CustomToscaFunction} from "../../../models/default-custom-functions";
76 import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
78 const SERVICE_SELF_TITLE = "SELF";
80 templateUrl: './properties-assignment.page.component.html',
81 styleUrls: ['./properties-assignment.page.component.less']
83 export class PropertiesAssignmentComponent {
84 title = "Properties & Inputs";
86 component: ComponentData;
87 componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
88 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
89 customToscaFunctions: Array<CustomToscaFunction> = [];
91 propertiesNavigationData = [];
92 instancesNavigationData = [];
94 instanceFePropertiesMap: InstanceFePropertiesMap;
95 inputs: Array<InputFEModel> = [];
96 policies: Array<PolicyInstance> = [];
97 instances: Array<ComponentInstance | GroupInstance | PolicyInstance> = [];
99 propertyStructureHeader: string;
101 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
102 selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = null;
103 checkedPropertiesCount: number = 0;
104 checkedChildPropertiesCount: number = 0;
105 enableToscaFunction: boolean = false;
106 checkedToscaCount: number = 0;
108 hierarchyPropertiesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
109 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
110 displayClearSearch = false;
111 searchPropertyName: string;
113 isInputsTabSelected: boolean;
114 isPropertiesTabSelected: boolean;
115 isPoliciesTabSelected: boolean;
117 resourceIsReadonly: boolean;
118 loadingInstances: boolean = false;
119 loadingInputs: boolean = false;
120 loadingPolicies: boolean = false;
121 loadingProperties: boolean = false;
122 changedData: Array<PropertyFEModel | InputFEModel>;
123 hasChangedData: boolean;
124 isValidChangedData: boolean;
125 savingChangedData: boolean;
126 stateChangeStartUnregister: Function;
127 serviceBePropertiesMap: InstanceBePropertiesMap;
128 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
129 selectedInstance_FlattenCapabilitiesList: Capability[];
130 componentInstancePropertyMap : PropertiesGroup;
131 defaultInputName: string;
132 doNotExtendBaseType: boolean;
134 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
135 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
136 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
138 constructor(private propertiesService: PropertiesService,
139 private hierarchyNavService: HierarchyNavService,
140 private propertiesUtils: PropertiesUtils,
141 private inputsUtils: InputsUtils,
142 private componentServiceNg2: ComponentServiceNg2,
143 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
144 private propertyCreatorComponent: PropertyCreatorComponent,
145 @Inject("$stateParams") _stateParams,
146 @Inject("$scope") private $scope: ng.IScope,
147 @Inject("$state") private $state: ng.ui.IStateService,
148 @Inject("Notification") private notification: any,
149 private componentModeService: ComponentModeService,
150 private eventListenerService: EventListenerService,
151 private ModalServiceSdcUI: SdcUiServices.ModalService,
152 private modalService: ModalService,
153 private keysPipe: KeysPipe,
154 private topologyTemplateService: TopologyTemplateService,
155 private translateService: TranslateService,
156 private service: ElementService) {
158 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
159 /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time
160 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
161 this.component = _stateParams.component;
162 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
163 this.updateViewMode();
164 this.changedData = [];
165 this.updateHasChangedData();
166 this.isValidChangedData = true;
170 console.debug("==>" + this.constructor.name + ": ngOnInit");
171 this.loadingInputs = true;
172 this.loadingPolicies = true;
173 this.loadingInstances = true;
174 this.loadingProperties = true;
175 this.topologyTemplateService
176 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
177 .subscribe(response => {
178 _.forEach(response.inputs, (input: InputBEModel) => {
179 const newInput: InputFEModel = new InputFEModel(input);
180 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
181 this.inputs.push(newInput); //only push items that were declared via SDC
183 this.componentInstancePropertyMap = response.componentInstancesProperties;
184 this.loadingInputs = false;
189 this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
190 for (let customFunction of data) {
191 this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
195 this.componentServiceNg2
196 .getComponentResourcePropertiesData(this.component)
197 .subscribe(response => {
198 this.loadingPolicies = false;
200 this.instances.push(...response.componentInstances);
201 this.instances.push(...response.groupInstances);
202 this.instances.push(...response.policies);
204 if (response.componentInstances) {
205 response.componentInstances.forEach(instance => {
206 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
208 iconClass: instance.iconClass,
209 originArchived: instance.originArchived
214 _.forEach(response.policies, (policy: any) => {
215 const newPolicy: InputFEModel = new InputFEModel(policy);
216 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
217 this.policies.push(policy);
220 // add the service self instance to the top of the list.
221 const serviceInstance = new ComponentInstance();
222 serviceInstance.name = SERVICE_SELF_TITLE;
223 serviceInstance.uniqueId = this.component.uniqueId;
224 this.instances.unshift(serviceInstance);
226 _.forEach(this.instances, (instance) => {
227 this.instancesNavigationData.push(instance);
228 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
230 iconClass: instance.iconClass,
231 originArchived: instance.originArchived
234 this.loadingInstances = false;
235 if (this.instancesNavigationData[0] == undefined) {
236 this.loadingProperties = false;
238 this.selectFirstInstanceByDefault();
240 this.loadingInstances = false;
242 let modelName = this.component.model ? this.component.model : null;
243 const categoryName= this.component.categories[0].name;
244 if (this.component.categories[0].name != null && this.component.model != null) {
245 this.service.getCategoryBaseTypes(categoryName, modelName).subscribe((response: ListBaseTypesResponse) => {
246 this.doNotExtendBaseType = response.doNotExtendBaseType;
247 this.loadingProperties = false;
252 this.loadingProperties = false;
255 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
256 // stop if has changed properties
257 if (this.hasChangedData) {
258 event.preventDefault();
259 this.showUnsavedChangesAlert().then(() => {
260 this.$state.go(toState, toParams);
266 this.loadDataTypesByComponentModel(this.component.model);
270 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
271 this.stateChangeStartUnregister();
274 selectFirstInstanceByDefault = () => {
275 if (this.instancesNavigationData[0] !== undefined) {
276 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
280 updateViewMode = () => {
281 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
284 onCheckout = (component: ComponentData) => {
285 this.component = component;
286 this.updateViewMode();
289 isSelf = (): boolean => {
290 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
293 showAddProperties = (): boolean => {
294 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
296 } else if (this.hideAddProperties()) {
299 return this.isSelf();
303 hideAddProperties = (): boolean => {
304 if (this.component.isService() && this.doNotExtendBaseType && this.isSelf) {
311 disablePropertyValue = () : boolean => {
312 if (this.component.isService() && this.doNotExtendBaseType && this.isSelf()){
318 getServiceProperties() {
319 this.loadingProperties = true;
320 this.topologyTemplateService
321 .getServiceProperties(this.component.uniqueId)
322 .subscribe((response) => {
323 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
324 this.serviceBePropertiesMap[this.component.uniqueId] = response;
325 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
326 this.loadingProperties = false;
328 this.loadingProperties = false;
332 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
333 // stop if has changed properties
334 if (this.hasChangedData) {
335 this.showUnsavedChangesAlert().then((resolve) => {
336 this.changeSelectedInstance(instance)
341 this.changeSelectedInstance(instance);
344 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
345 this.selectedInstanceData = instance;
346 this.loadingProperties = true;
347 if (instance instanceof ComponentInstance) {
348 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
349 if (this.isInput(instance.originType)) {
350 this.componentInstanceServiceNg2
351 .getComponentInstanceInputs(this.component, instance)
352 .subscribe(response => {
353 instanceBePropertiesMap[instance.uniqueId] = response;
354 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
358 this.loadingProperties = false;
360 } else if (this.isSelf()) {
361 this.getServiceProperties();
363 this.componentInstanceServiceNg2
364 .getComponentInstanceProperties(this.component, instance.uniqueId)
365 .subscribe(response => {
366 instanceBePropertiesMap[instance.uniqueId] = response;
367 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
371 this.loadingProperties = false;
374 this.loadingProperties = false;
375 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
376 } else if (instance instanceof GroupInstance) {
377 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
378 this.componentInstanceServiceNg2
379 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
380 .subscribe((response) => {
381 instanceBePropertiesMap[instance.uniqueId] = response;
382 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
386 this.loadingProperties = false;
388 } else if (instance instanceof PolicyInstance) {
389 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
390 this.componentInstanceServiceNg2
391 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
392 .subscribe((response) => {
393 instanceBePropertiesMap[instance.uniqueId] = response;
394 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
398 this.loadingProperties = false;
401 this.loadingProperties = false;
404 if (this.searchPropertyName) {
407 //clear selected property from the navigation
408 this.selectedFlatProperty = new SimpleFlatProperty();
409 this.propertiesNavigationData = [];
410 this.checkedToscaCount = 0;
411 this.enableToscaFunction = false;
415 * Entry point handling response from server
417 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
418 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
419 this.checkedPropertiesCount = 0;
420 this.checkedChildPropertiesCount = 0;
423 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
424 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
425 let currentUniqueId = this.selectedInstanceData.uniqueId;
426 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
427 let isCapabilityOwnedByInstance: boolean;
428 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
429 this.selectedInstance_FlattenCapabilitiesList,
430 (result, cap: Capability) => {
431 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
432 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
433 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
434 if (cap.properties && isCapabilityOwnedByInstance) {
435 _.forEach(cap.properties, prop => {
436 if (!prop.origName) {
437 prop.origName = prop.name;
438 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
441 return result.concat(cap.properties);
445 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
446 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
447 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
448 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
450 //concatenate capabilitiesProps to all props list
451 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
452 this.checkedPropertiesCount = 0;
455 isCapabilityProperty = (prop: PropertyBEModel) => {
456 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
459 /*** VALUE CHANGE EVENTS ***/
460 dataChanged = (item: PropertyFEModel | InputFEModel) => {
462 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
463 itemHasChanged = item.hasValueObjChanged();
464 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
465 itemHasChanged = item.hasChanged();
466 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
467 itemHasChanged = item.hasDefaultValueChanged();
470 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
471 if (itemHasChanged) {
472 if (dataChangedIdx === -1) {
473 this.changedData.push(item);
476 if (dataChangedIdx !== -1) {
477 this.changedData.splice(dataChangedIdx, 1);
481 if (this.isPropertiesTabSelected) {
482 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
483 } else if (this.isInputsTabSelected) {
484 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
485 } else if (this.isPoliciesTabSelected) {
486 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
488 this.updateHasChangedData();
492 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
495 * Handle select node in navigation area, and select the row in table
497 onPropertySelectedUpdate = ($event) => {
498 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
499 this.selectedFlatProperty = $event;
500 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
501 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
505 * When user select row in table, this will prepare the hirarchy object for the tree.
507 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
508 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
509 let property = propertyRowSelectedEvent.propertyModel;
510 let instanceName = propertyRowSelectedEvent.instanceName;
511 this.propertyStructureHeader = null;
513 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
514 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
515 let simpleFlatProperty: Array<SimpleFlatProperty>;
516 if (property instanceof PropertyFEModel) {
517 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
518 } else if (property instanceof DerivedFEProperty) {
519 // Need to find parent PropertyFEModel
520 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
521 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
523 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
525 this.propertiesNavigationData = simpleFlatProperty;
528 // Update the header in the navigation tree with property name.
529 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
531 // Set selected property in table
532 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
533 this.hierarchyNavTabs.triggerTabChange('Property Structure');
537 selectInstanceRow = ($event) => {//get instance name
538 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
539 return instance.name == $event;
541 this.hierarchyNavTabs.triggerTabChange('Composition');
544 tabChanged = (event) => {
545 // stop if has changed properties
546 if (this.hasChangedData) {
547 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
548 this.showUnsavedChangesAlert().then((proceed) => {
549 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
555 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
556 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
557 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
558 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
559 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
560 this.propertyStructureHeader = null;
561 this.searchQuery = '';
565 * Select Tosca function value from defined values
567 selectToscaFunctionAndValues = (): void => {
568 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
569 if (!selectedInstanceData) {
572 this.openToscaGetFunctionModal();
575 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
576 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
577 const instanceId: string = instancesIds[0];
578 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
579 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
582 private buildCheckedInstanceProperty(): PropertyBEModel {
583 return this.buildCheckedInstanceProperties()[0];
586 private buildCheckedInstanceProperties(): PropertyBEModel[] {
587 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
588 const instanceId: string = instancesIds[0];
589 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
592 private openToscaGetFunctionModal() {
593 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
594 const modalButtons = [];
595 let disableSaveButtonFlag = true;
596 const modal = this.modalService.createCustomModal(new ModalModel(
603 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
605 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
606 if (toscaGetFunction) {
607 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
609 this.clearCheckedInstancePropertyValue();
611 this.modalService.closeCurrentModal();
613 (): boolean => { return disableSaveButtonFlag }
615 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
616 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
617 this.modalService.closeCurrentModal();
621 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
622 'property': checkedInstanceProperty,
623 'componentInstanceMap': this.componentInstanceMap,
624 'customToscaFunctions': this.customToscaFunctions
626 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
627 disableSaveButtonFlag = !validationEvent.isValid;
629 modal.instance.open();
632 private clearCheckedInstancePropertyValue() {
633 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
634 const currentValue : any = checkedInstanceProperty.value;
635 checkedInstanceProperty.getInputValues = null;
636 checkedInstanceProperty.value = null;
637 checkedInstanceProperty.toscaFunction = null;
638 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
639 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
640 const parts = propertiesNameArray.split("#");
641 let currentKey = (<DerivedFEProperty>checkedInstanceProperty.input).toscaPath;
642 if (propertiesNameArray.length > 1){
643 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
644 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
646 if (this.enableToscaFunction) {
647 this.processSubtoscaFunction(checkedInstanceProperty,null);
651 if (this.selectedInstanceData instanceof ComponentInstance) {
652 var toRemove = this.changedData.filter(obj => {
653 return obj.name == checkedInstanceProperty.name && obj.type == checkedInstanceProperty.type && obj.value == null;
655 const index: number = this.changedData.indexOf(toRemove[0]);
657 this.changedData.splice(index, 1);
659 this.updateInstanceProperty(checkedInstanceProperty);
660 } else if (this.selectedInstanceData instanceof GroupInstance) {
661 this.updateGroupInstanceProperty(checkedInstanceProperty);
662 } else if (this.selectedInstanceData instanceof PolicyInstance) {
663 this.updatePolicyInstanceProperty(checkedInstanceProperty);
667 private processSubtoscaFunction(checkedProperty : PropertyDeclareAPIModel, toscaFunction: ToscaFunction) {
668 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
669 const instanceId: string = instancesIds[0];
670 this.instanceFePropertiesMap[instanceId].forEach(prop => {
671 if (prop.flattenedChildren) {
672 prop.flattenedChildren.forEach((child) => {
673 if (child.isSelected && !child.isDeclared && !child.isDisabled) {
674 prop.subPropertyToscaFunctions = checkedProperty.subPropertyToscaFunctions;
676 child.value = toscaFunction.buildValueString();
677 child.valueObj = toscaFunction.buildValueObject();
678 child.toscaFunction = toscaFunction;
679 this.hasChangedData = true;
680 if (this.changedData.length == 0) {
681 this.changedData.push(prop);
684 child.valueObj = null;
685 child.toscaFunction = null;
687 child.isSelected = false;
688 this.togggleToscaBtn(false);
695 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
696 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
697 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
698 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
699 const parts = propertiesName.split("#");
700 let currentKey = (<DerivedFEProperty>checkedProperty.input).toscaPath;
701 if (checkedProperty.subPropertyToscaFunctions == null){
702 checkedProperty.subPropertyToscaFunctions = [];
704 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
705 if (!subPropertyToscaFunction){
706 subPropertyToscaFunction = new SubPropertyToscaFunction();
707 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
709 subPropertyToscaFunction.toscaFunction = toscaFunction;
710 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
711 if (this.enableToscaFunction) {
712 this.processSubtoscaFunction(checkedProperty,toscaFunction);
716 checkedProperty.subPropertyToscaFunctions = null;
717 checkedProperty.toscaFunction = toscaFunction;
719 if (this.selectedInstanceData instanceof ComponentInstance) {
720 this.updateInstanceProperty(checkedProperty);
721 } else if (this.selectedInstanceData instanceof GroupInstance) {
722 this.updateGroupInstanceProperty(checkedProperty);
723 } else if (this.selectedInstanceData instanceof PolicyInstance) {
724 this.updatePolicyInstanceProperty(checkedProperty);
728 private isComplexSchemaType(propertyType: string): boolean {
729 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
732 private isListOrMap(propertyType: string): boolean {
733 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
736 private areEqual(array1: string[], array2: string[]): boolean {
737 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
740 updateInstanceProperty(instanceProperty: PropertyBEModel) {
741 this.loadingProperties = true;
742 this.enableToscaFunction = false;
743 this.checkedToscaCount = 0;
745 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
746 this.selectedInstanceData.uniqueId, [instanceProperty])
748 this.changeSelectedInstance(this.getSelectedInstance());
750 this.loadingProperties = false;
751 console.error(error);
753 this.loadingProperties = false;
757 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
758 this.loadingProperties = true;
759 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
760 this.selectedInstanceData.uniqueId, [instanceProperty])
762 this.changeSelectedInstance(this.getSelectedInstance());
764 this.loadingProperties = false;
765 console.error(error);
767 this.loadingProperties = false;
771 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
772 this.loadingProperties = true;
773 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
774 this.selectedInstanceData.uniqueId, [instanceProperty])
776 this.changeSelectedInstance(this.getSelectedInstance());
778 this.loadingProperties = false;
779 console.error(error);
781 this.loadingProperties = false;
785 declareInput = (): void => {
786 if (this.checkedPropertiesCount == 1) {
787 this.openAddInputNameAndDeclareInputModal();
788 } else if (this.checkedPropertiesCount > 1) {
789 this.declareInputFromProperties();
793 /*** DECLARE PROPERTIES/INPUTS ***/
794 declareInputFromProperties = (inputName?: string): void => {
795 console.debug("==>" + this.constructor.name + ": declareProperties");
797 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
798 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
799 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
800 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
801 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
803 angular.forEach(instancesIds, (instanceId: string): void => {
804 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
805 if (selectedInstanceData instanceof ComponentInstance) {
806 if (!this.isInput(selectedInstanceData.originType)) {
807 // convert Property FE model -> Property BE model, extract only checked
808 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
810 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
813 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
815 } else if (selectedInstanceData instanceof GroupInstance) {
816 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
817 } else if (selectedInstanceData instanceof PolicyInstance) {
818 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
822 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
824 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
825 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
826 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
828 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
829 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
832 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
833 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
834 prop => !this.isCapabilityProperty(prop)
836 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
837 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
840 let isCapabilityPropertyChanged = false;
842 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
843 (prop: PropertyBEModel) => {
844 prop.name = prop.origName || prop.name;
845 if (this.isCapabilityProperty(prop)) {
846 isCapabilityPropertyChanged = true;
850 this.topologyTemplateService
851 .createInput(this.component, inputsToCreate, this.isSelf())
852 .subscribe((response) => {
853 this.selectInstanceRow(SERVICE_SELF_TITLE);
854 this.onInstanceSelectedUpdate(this.instances[0]);
855 this.setInputTabIndication(response.length);
856 this.checkedPropertiesCount = 0;
857 this.checkedChildPropertiesCount = 0;
858 _.forEach(response, (input: InputBEModel) => {
859 const newInput: InputFEModel = new InputFEModel(input);
860 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
861 this.inputs.push(newInput);
862 this.updatePropertyValueAfterDeclare(newInput);
864 if (isCapabilityPropertyChanged) {
865 this.reloadInstanceCapabilities();
867 }, error => {}); //ignore error
870 generateDefaultInputName = (): string => {
871 let defaultInputName: string;
872 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
873 angular.forEach(instancesIds, (instanceId: string) => {
874 let selectedProperty: PropertyBEModel = new PropertyBEModel(this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId])[0]);
875 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
876 defaultInputName = this.generateInputName(selectedInstanceData.invariantName, selectedProperty.name);
878 return defaultInputName;
881 private generateInputName = (componentName: string, propertyName: string): string => {
882 let inputName: string;
884 if (propertyName.includes("::")) {
885 propertyName = propertyName.replace(/::/g, "_");
888 inputName = componentName + "_" + propertyName;
890 inputName = propertyName;
896 private openAddInputNameAndDeclareInputModal = (): void => {
897 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
898 const modalButtons = [];
899 const modal = this.modalService.createCustomModal(new ModalModel(
906 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
908 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
910 this.declareInputFromProperties(inputName);
912 this.notification.warning({
913 message: 'Failed to set input name',
917 this.modalService.closeCurrentModal();
920 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
921 this.modalService.closeCurrentModal();
923 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultInputName()});
924 modal.instance.open();
927 declareListProperties = (): void => {
928 // get selected properties
929 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
930 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
931 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
932 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
933 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
934 let propertyNameList: Array<string> = [];
937 angular.forEach(instancesIds, (instanceId: string): void => {
939 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
940 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
942 if (selectedInstanceData instanceof ComponentInstance) {
943 if (!this.isInput(selectedInstanceData.originType)) {
944 // convert Property FE model -> Property BE model, extract only checked
945 selectedComponentInstancesProperties[instanceId] = checkedProperties;
947 selectedComponentInstancesInputs[instanceId] = checkedProperties;
949 } else if (selectedInstanceData instanceof GroupInstance) {
950 selectedGroupInstancesProperties[instanceId] = checkedProperties;
951 } else if (selectedInstanceData instanceof PolicyInstance) {
952 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
955 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
956 propertyNameList.push(property.name);
960 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
962 let modalTitle = 'Declare Properties as List Input';
963 const modal = this.modalService.createCustomModal(new ModalModel(
965 modalTitle, /* title */
970 'blue', /* css class */
971 () => { /* callback */
972 let content:any = modal.instance.dynamicContent.instance;
975 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
976 let typelist: any = PROPERTY_TYPES.LIST;
977 let uniID: any = insId;
978 let boolfalse: any = false;
979 let required: any = content.propertyModel.required;
983 "type": content.propertyModel.simpleType,
987 let schemaProp :any = {
988 "type": content.propertyModel.simpleType,
992 reglistInput.description = content.propertyModel.description;
993 reglistInput.name = content.propertyModel.name;
994 reglistInput.type = typelist;
995 reglistInput.schemaType = content.propertyModel.simpleType;
996 reglistInput.instanceUniqueId = uniID;
997 reglistInput.uniqueId = uniID;
998 reglistInput.required = required;
999 reglistInput.schema = schem;
1000 reglistInput.schemaProperty = schemaProp;
1003 componentInstInputsMap: content.inputsToCreate,
1004 listInput: reglistInput
1007 this.topologyTemplateService
1008 .createListInput(this.component, input, this.isSelf())
1009 .subscribe(response => {
1010 this.setInputTabIndication(response.length);
1011 this.checkedPropertiesCount = 0;
1012 this.checkedChildPropertiesCount = 0;
1013 _.forEach(response, (input: InputBEModel) => {
1014 let newInput: InputFEModel = new InputFEModel(input);
1015 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
1016 this.inputs.push(newInput);
1017 // create list input does not return updated properties info, so need to reload
1018 //this.updatePropertyValueAfterDeclare(newInput);
1019 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1020 this.changeSelectedInstance(this.selectedInstanceData);
1022 modal.instance.close();
1024 }, error => {}); //ignore error
1027 /*, getDisabled: function */
1029 new ButtonModel('Cancel', 'outline grey', () => {
1030 modal.instance.close();
1035 // 3rd arg is passed to DeclareListComponent instance
1036 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
1037 modal.instance.open();
1040 /*** DECLARE PROPERTIES/POLICIES ***/
1041 declarePropertiesToPolicies = (): void => {
1042 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
1043 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
1045 angular.forEach(instancesIds, (instanceId: string): void => {
1046 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
1047 if (selectedInstanceData instanceof ComponentInstance) {
1048 if (!this.isInput(selectedInstanceData.originType)) {
1049 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
1054 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
1055 this.loadingPolicies = true;
1057 this.topologyTemplateService
1058 .createPolicy(this.component, policiesToCreate, this.isSelf())
1059 .subscribe(response => {
1060 this.setPolicyTabIndication(response.length);
1061 this.checkedPropertiesCount = 0;
1062 this.displayPoliciesAsDeclared(response);
1063 this.loadingPolicies = false;
1068 displayPoliciesAsDeclared = (policies) => {
1069 _.forEach(policies, (policy: any) => {
1070 let newPolicy: InputFEModel = new InputFEModel(policy);
1071 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
1072 newPolicy.relatedPropertyName = policy.name;
1073 newPolicy.relatedPropertyValue = policy.value;
1074 this.updatePropertyValueAfterDeclare(newPolicy);
1075 this.policies.push(policy);
1079 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
1080 return new Promise((resolve, reject) => {
1081 if (!this.isValidChangedData) {
1082 reject('Changed data is invalid - cannot save!');
1085 if (!this.changedData.length) {
1090 // make request and its handlers
1092 let handleSuccess, handleError;
1093 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1094 if (this.isPropertiesTabSelected) {
1095 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1096 changedProp = <PropertyFEModel>changedProp;
1097 const propBE = new PropertyBEModel(changedProp);
1098 propBE.toscaPresentation = new ToscaPresentationData();
1099 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1100 propBE.value = changedProp.getJSONValue();
1101 propBE.name = changedProp.origName || changedProp.name;
1102 delete propBE.origName;
1105 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1107 if (this.selectedInstanceData instanceof ComponentInstance) {
1108 if (this.isInput(this.selectedInstanceData.originType)) {
1109 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1110 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1111 request = Observable.forkJoin(
1112 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1113 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1114 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1117 else if (changedInputsProperties.length) {
1118 request = this.componentInstanceServiceNg2
1119 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1121 else if (changedCapabilitiesProperties.length) {
1122 request = this.componentInstanceServiceNg2
1123 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1125 handleSuccess = (response) => {
1126 // reset each changed property with new value and remove it from changed properties list
1127 response.forEach((resInput) => {
1128 const changedProp = <PropertyFEModel>this.changedData.shift();
1129 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1133 if (this.isSelf()) {
1134 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1135 delete cp.constraints;
1139 request = this.componentInstanceServiceNg2
1140 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1142 handleSuccess = (response) => {
1143 // reset each changed property with new value and remove it from changed properties list
1144 response.forEach((resProp) => {
1145 const changedProp = <PropertyFEModel>this.changedData.shift();
1146 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1151 } else if (this.selectedInstanceData instanceof GroupInstance) {
1152 request = this.componentInstanceServiceNg2
1153 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1154 handleSuccess = (response) => {
1155 // reset each changed property with new value and remove it from changed properties list
1156 response.forEach((resProp) => {
1157 const changedProp = <PropertyFEModel>this.changedData.shift();
1158 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1162 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1163 request = this.componentInstanceServiceNg2
1164 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1165 handleSuccess = (response) => {
1166 // reset each changed property with new value and remove it from changed properties list
1167 response.forEach((resProp) => {
1168 const changedProp = <PropertyFEModel>this.changedData.shift();
1169 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1174 } else if (this.isInputsTabSelected) {
1176 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1177 changedInput = <InputFEModel>changedInput;
1178 const inputBE = new InputBEModel(changedInput);
1179 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1182 request = this.componentServiceNg2
1183 .updateComponentInputs(this.component, changedInputs);
1184 handleSuccess = (response) => {
1185 // reset each changed property with new value and remove it from changed properties list
1186 response.forEach((resInput) => {
1187 const changedInput = <InputFEModel>this.changedData.shift();
1188 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1189 changedInput.required = resInput.required;
1190 changedInput.requiredOrig = resInput.required;
1195 this.savingChangedData = true;
1198 this.savingChangedData = false;
1199 if (changedCapabilitiesProperties.length) {
1200 this.reloadInstanceCapabilities();
1202 handleSuccess && handleSuccess(response);
1203 this.updateHasChangedData();
1207 this.savingChangedData = false;
1208 handleError && handleError(error);
1209 this.updateHasChangedData();
1216 reloadInstanceCapabilities = (): void => {
1217 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1218 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1219 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1220 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1221 return instance.capabilities;
1224 }, new CapabilitiesGroup());
1225 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1229 reverseChangedData = ():void => {
1230 // make reverse item handler
1231 let handleReverseItem;
1232 if (this.isPropertiesTabSelected) {
1233 handleReverseItem = (changedItem) => {
1234 changedItem = <PropertyFEModel>changedItem;
1235 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1237 } else if (this.isInputsTabSelected) {
1238 handleReverseItem = (changedItem) => {
1239 changedItem = <InputFEModel>changedItem;
1240 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1241 changedItem.resetMetadata();
1242 changedItem.required = changedItem.requiredOrig;
1246 this.changedData.forEach(handleReverseItem);
1247 this.changedData = [];
1248 this.updateHasChangedData();
1251 updateHasChangedData = ():boolean => {
1252 const curHasChangedData:boolean = (this.changedData.length > 0);
1253 if (curHasChangedData !== this.hasChangedData) {
1254 this.hasChangedData = curHasChangedData;
1255 if(this.hasChangedData) {
1256 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1258 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1261 return this.hasChangedData;
1264 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1265 this.saveChangedData().then(
1267 this.notification.success({
1268 message: 'Successfully saved changes',
1271 if(onSuccessFunction) onSuccessFunction();
1274 this.notification.error({
1275 message: 'Failed to save changes!',
1278 if(onError) onError();
1283 showUnsavedChangesAlert = ():Promise<any> => {
1284 let modalTitle:string;
1285 if (this.isPropertiesTabSelected) {
1286 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1287 } else if (this.isInputsTabSelected) {
1288 modalTitle = `Unsaved inputs for ${this.component.name}`;
1291 return new Promise<any>((resolve, reject) => {
1292 const modal = this.ModalServiceSdcUI.openCustomModal(
1296 type: SdcUiCommon.ModalType.custom,
1297 testId: "navigate-modal",
1300 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1301 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1302 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1303 ] as SdcUiCommon.IModalButtonComponent[]
1304 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1309 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1310 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1311 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1312 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1313 return feProperty.name == input.relatedPropertyName &&
1314 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1316 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1317 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1318 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1319 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1323 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1324 updateCheckedPropertyCount = (increment: boolean): void => {
1325 this.checkedPropertiesCount += (increment) ? 1 : -1;
1326 this.checkedToscaCount = 0;
1327 this.enableToscaFunction = false;
1328 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1331 updateCheckedChildPropertyCount = (increment: boolean): void => {
1332 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1335 togggleToscaBtn = (toscaFlag: boolean) : void => {
1336 this.checkedToscaCount += toscaFlag ? 1 : -1;
1337 if(this.checkedToscaCount == 1){
1338 this.enableToscaFunction = true;
1340 this.enableToscaFunction = false;
1344 setInputTabIndication = (numInputs: number): void => {
1345 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1348 setPolicyTabIndication = (numPolicies: number): void => {
1349 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1352 resetUnsavedChangesForInput = (input:InputFEModel) => {
1353 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1354 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1355 this.updateHasChangedData();
1358 deleteInput = (input: InputFEModel) => {
1359 //reset any unsaved changes to the input before deleting it
1360 this.resetUnsavedChangesForInput(input);
1362 console.debug("==>" + this.constructor.name + ": deleteInput");
1363 let inputToDelete = new InputBEModel(input);
1365 this.componentServiceNg2
1366 .deleteInput(this.component, inputToDelete)
1367 .subscribe(response => {
1368 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1370 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1371 this.changeSelectedInstance(this.selectedInstanceData);
1372 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1374 // if (instanceFeProperties) {
1375 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1376 // return prop.name == input.propertyName;
1379 // if (propToEnable) {
1380 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1381 // propToEnable.setNonDeclared(response.inputPath);
1382 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1383 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1386 }, error => {}); //ignore error
1389 deletePolicy = (policy: PolicyInstance) => {
1390 this.loadingPolicies = true;
1391 this.topologyTemplateService
1392 .deletePolicy(this.component, policy)
1393 .subscribe((response) => {
1394 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1395 this.changeSelectedInstance(this.selectedInstanceData);
1396 this.loadingPolicies = false;
1400 deleteProperty = (property: PropertyFEModel) => {
1401 const propertyToDelete = new PropertyFEModel(property);
1402 this.loadingProperties = true;
1403 const feMap = this.instanceFePropertiesMap;
1404 this.topologyTemplateService
1405 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1406 .subscribe((response) => {
1407 const props = feMap[this.component.uniqueId];
1408 props.splice(props.findIndex(p => p.uniqueId === response),1);
1409 this.loadingProperties = false;
1411 this.loadingProperties = false;
1412 console.error(error);
1416 /*** addProperty ***/
1417 addProperty = (model: string) => {
1418 this.loadDataTypesByComponentModel(model)
1419 let modalTitle = 'Add Property';
1420 let modal = this.modalService.createCustomModal(new ModalModel(
1425 new ButtonModel('Save', 'blue', () => {
1426 modal.instance.dynamicContent.instance.isLoading = true;
1427 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1428 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1429 .subscribe((response) => {
1430 modal.instance.dynamicContent.instance.isLoading = false;
1431 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1432 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1433 modal.instance.close();
1435 modal.instance.dynamicContent.instance.isLoading = false;
1436 this.notification.error({
1437 message: 'Failed to add property:' + error,
1441 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1442 new ButtonModel('Cancel', 'outline grey', () => {
1443 modal.instance.close();
1448 modal.instance.open();
1449 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1454 let modalTitle = 'Add Input';
1455 let modal = this.modalService.createCustomModal(new ModalModel(
1460 new ButtonModel('Save', 'blue', () => {
1461 modal.instance.dynamicContent.instance.isLoading = true;
1462 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1463 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1464 .subscribe((response) => {
1465 modal.instance.dynamicContent.instance.isLoading = false;
1466 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1467 this.inputs.push(newInputProp);
1468 modal.instance.close();
1470 modal.instance.dynamicContent.instance.isLoading = false;
1471 this.notification.error({
1472 message: 'Failed to add input:' + error,
1476 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1477 new ButtonModel('Cancel', 'outline grey', () => {
1478 modal.instance.close();
1483 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1484 modal.instance.open();
1487 /*** SEARCH RELATED FUNCTIONS ***/
1488 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1489 let instanceBePropertiesMap:InstanceBePropertiesMap;
1490 this.componentServiceNg2
1491 .filterComponentInstanceProperties(this.component, filterData)
1492 .subscribe((response) => {
1493 this.processInstancePropertiesResponse(response, false);
1494 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1495 this.searchPropertyName = filterData.propertyName;//mark in table
1496 this.hierarchyNavTabs.triggerTabChange('Composition');
1497 this.propertiesNavigationData = [];
1498 this.displayClearSearch = true;
1499 }, (error) => {}); //ignore error
1503 clearSearch = () => {
1504 this.instancesNavigationData = this.instances;
1505 this.searchPropertyName = "";
1506 this.hierarchyPropertiesDisplayOptions.searchText = "";
1507 this.displayClearSearch = false;
1508 this.advanceSearch.clearAll();
1509 this.searchQuery = '';
1512 clickOnClearSearch = () => {
1514 this.selectFirstInstanceByDefault();
1515 this.hierarchyNavTabs.triggerTabChange('Composition');
1518 private isInput = (instanceType:string):boolean =>{
1519 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1522 loadDataTypesByComponentModel(model:string) {
1523 this.propertyCreatorComponent.filterDataTypesByModel(model);