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;
128 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
129 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
130 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
132 constructor(private propertiesService: PropertiesService,
133 private hierarchyNavService: HierarchyNavService,
134 private propertiesUtils: PropertiesUtils,
135 private inputsUtils: InputsUtils,
136 private componentServiceNg2: ComponentServiceNg2,
137 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
138 private propertyCreatorComponent: PropertyCreatorComponent,
139 @Inject("$stateParams") _stateParams,
140 @Inject("$scope") private $scope: ng.IScope,
141 @Inject("$state") private $state: ng.ui.IStateService,
142 @Inject("Notification") private notification: any,
143 private componentModeService: ComponentModeService,
144 private eventListenerService: EventListenerService,
145 private ModalServiceSdcUI: SdcUiServices.ModalService,
146 private modalService: ModalService,
147 private keysPipe: KeysPipe,
148 private topologyTemplateService: TopologyTemplateService,
149 private translateService: TranslateService) {
151 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
152 /* 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
153 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
154 this.component = _stateParams.component;
155 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
156 this.updateViewMode();
157 this.changedData = [];
158 this.updateHasChangedData();
159 this.isValidChangedData = true;
163 console.debug("==>" + this.constructor.name + ": ngOnInit");
164 this.loadingInputs = true;
165 this.loadingPolicies = true;
166 this.loadingInstances = true;
167 this.loadingProperties = true;
168 this.topologyTemplateService
169 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
170 .subscribe(response => {
171 _.forEach(response.inputs, (input: InputBEModel) => {
172 const newInput: InputFEModel = new InputFEModel(input);
173 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
174 this.inputs.push(newInput); //only push items that were declared via SDC
176 this.componentInstancePropertyMap = response.componentInstancesProperties;
177 this.loadingInputs = false;
181 this.componentServiceNg2
182 .getComponentResourcePropertiesData(this.component)
183 .subscribe(response => {
184 this.loadingPolicies = false;
186 this.instances.push(...response.componentInstances);
187 this.instances.push(...response.groupInstances);
188 this.instances.push(...response.policies);
190 if (response.componentInstances) {
191 response.componentInstances.forEach(instance => {
192 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
194 iconClass: instance.iconClass,
195 originArchived: instance.originArchived
200 _.forEach(response.policies, (policy: any) => {
201 const newPolicy: InputFEModel = new InputFEModel(policy);
202 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
203 this.policies.push(policy);
206 // add the service self instance to the top of the list.
207 const serviceInstance = new ComponentInstance();
208 serviceInstance.name = SERVICE_SELF_TITLE;
209 serviceInstance.uniqueId = this.component.uniqueId;
210 this.instances.unshift(serviceInstance);
212 _.forEach(this.instances, (instance) => {
213 this.instancesNavigationData.push(instance);
214 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
216 iconClass: instance.iconClass,
217 originArchived: instance.originArchived
220 this.loadingInstances = false;
221 if (this.instancesNavigationData[0] == undefined) {
222 this.loadingProperties = false;
224 this.selectFirstInstanceByDefault();
226 this.loadingInstances = false;
229 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
230 // stop if has changed properties
231 if (this.hasChangedData) {
232 event.preventDefault();
233 this.showUnsavedChangesAlert().then(() => {
234 this.$state.go(toState, toParams);
240 this.loadDataTypesByComponentModel(this.component.model);
244 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
245 this.stateChangeStartUnregister();
248 selectFirstInstanceByDefault = () => {
249 if (this.instancesNavigationData[0] !== undefined) {
250 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
254 updateViewMode = () => {
255 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
258 onCheckout = (component: ComponentData) => {
259 this.component = component;
260 this.updateViewMode();
263 isSelf = (): boolean => {
264 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
267 showAddProperties = (): boolean => {
268 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
271 return this.isSelf();
274 getServiceProperties() {
275 this.loadingProperties = true;
276 this.topologyTemplateService
277 .getServiceProperties(this.component.uniqueId)
278 .subscribe((response) => {
279 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
280 this.serviceBePropertiesMap[this.component.uniqueId] = response;
281 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
282 this.loadingProperties = false;
284 this.loadingProperties = false;
288 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
289 // stop if has changed properties
290 if (this.hasChangedData) {
291 this.showUnsavedChangesAlert().then((resolve) => {
292 this.changeSelectedInstance(instance)
297 this.changeSelectedInstance(instance);
300 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
301 this.selectedInstanceData = instance;
302 this.loadingProperties = true;
303 if (instance instanceof ComponentInstance) {
304 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
305 if (this.isInput(instance.originType)) {
306 this.componentInstanceServiceNg2
307 .getComponentInstanceInputs(this.component, instance)
308 .subscribe(response => {
309 instanceBePropertiesMap[instance.uniqueId] = response;
310 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
314 this.loadingProperties = false;
316 } else if (this.isSelf()) {
317 this.getServiceProperties();
319 this.componentInstanceServiceNg2
320 .getComponentInstanceProperties(this.component, instance.uniqueId)
321 .subscribe(response => {
322 instanceBePropertiesMap[instance.uniqueId] = response;
323 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
327 this.loadingProperties = false;
330 this.loadingProperties = false;
331 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
332 } else if (instance instanceof GroupInstance) {
333 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
334 this.componentInstanceServiceNg2
335 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
336 .subscribe((response) => {
337 instanceBePropertiesMap[instance.uniqueId] = response;
338 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
342 this.loadingProperties = false;
344 } else if (instance instanceof PolicyInstance) {
345 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
346 this.componentInstanceServiceNg2
347 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
348 .subscribe((response) => {
349 instanceBePropertiesMap[instance.uniqueId] = response;
350 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
354 this.loadingProperties = false;
357 this.loadingProperties = false;
360 if (this.searchPropertyName) {
363 //clear selected property from the navigation
364 this.selectedFlatProperty = new SimpleFlatProperty();
365 this.propertiesNavigationData = [];
369 * Entry point handling response from server
371 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
372 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
373 this.checkedPropertiesCount = 0;
374 this.checkedChildPropertiesCount = 0;
377 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
378 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
379 let currentUniqueId = this.selectedInstanceData.uniqueId;
380 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
381 let isCapabilityOwnedByInstance: boolean;
382 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
383 this.selectedInstance_FlattenCapabilitiesList,
384 (result, cap: Capability) => {
385 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
386 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
387 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
388 if (cap.properties && isCapabilityOwnedByInstance) {
389 _.forEach(cap.properties, prop => {
390 if (!prop.origName) {
391 prop.origName = prop.name;
392 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
395 return result.concat(cap.properties);
399 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
400 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
401 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
402 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
404 //concatenate capabilitiesProps to all props list
405 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
406 this.checkedPropertiesCount = 0;
409 isCapabilityProperty = (prop: PropertyBEModel) => {
410 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
413 /*** VALUE CHANGE EVENTS ***/
414 dataChanged = (item: PropertyFEModel | InputFEModel) => {
416 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
417 itemHasChanged = item.hasValueObjChanged();
418 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
419 itemHasChanged = item.hasChanged();
420 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
421 itemHasChanged = item.hasDefaultValueChanged();
424 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
425 if (itemHasChanged) {
426 if (dataChangedIdx === -1) {
427 this.changedData.push(item);
430 if (dataChangedIdx !== -1) {
431 this.changedData.splice(dataChangedIdx, 1);
435 if (this.isPropertiesTabSelected) {
436 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
437 } else if (this.isInputsTabSelected) {
438 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
439 } else if (this.isPoliciesTabSelected) {
440 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
442 this.updateHasChangedData();
446 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
449 * Handle select node in navigation area, and select the row in table
451 onPropertySelectedUpdate = ($event) => {
452 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
453 this.selectedFlatProperty = $event;
454 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
455 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
459 * When user select row in table, this will prepare the hirarchy object for the tree.
461 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
462 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
463 let property = propertyRowSelectedEvent.propertyModel;
464 let instanceName = propertyRowSelectedEvent.instanceName;
465 this.propertyStructureHeader = null;
467 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
468 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
469 let simpleFlatProperty: Array<SimpleFlatProperty>;
470 if (property instanceof PropertyFEModel) {
471 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
472 } else if (property instanceof DerivedFEProperty) {
473 // Need to find parent PropertyFEModel
474 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
475 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
477 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
479 this.propertiesNavigationData = simpleFlatProperty;
482 // Update the header in the navigation tree with property name.
483 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
485 // Set selected property in table
486 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
487 this.hierarchyNavTabs.triggerTabChange('Property Structure');
491 selectInstanceRow = ($event) => {//get instance name
492 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
493 return instance.name == $event;
495 this.hierarchyNavTabs.triggerTabChange('Composition');
498 tabChanged = (event) => {
499 // stop if has changed properties
500 if (this.hasChangedData) {
501 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
502 this.showUnsavedChangesAlert().then((proceed) => {
503 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
509 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
510 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
511 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
512 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
513 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
514 this.propertyStructureHeader = null;
515 this.searchQuery = '';
519 * Select Tosca function value from defined values
521 selectToscaFunctionAndValues = (): void => {
522 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
523 if (!selectedInstanceData) {
526 this.openToscaGetFunctionModal();
529 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
530 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
531 const instanceId: string = instancesIds[0];
532 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
533 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
536 private buildCheckedInstanceProperty(): PropertyBEModel {
537 return this.buildCheckedInstanceProperties()[0];
540 private buildCheckedInstanceProperties(): PropertyBEModel[] {
541 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
542 const instanceId: string = instancesIds[0];
543 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
546 private openToscaGetFunctionModal() {
547 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
548 const modalButtons = [];
549 let disableSaveButtonFlag = true;
550 const modal = this.modalService.createCustomModal(new ModalModel(
557 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
559 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
560 if (toscaGetFunction) {
561 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
563 this.clearCheckedInstancePropertyValue();
565 this.modalService.closeCurrentModal();
567 (): boolean => { return disableSaveButtonFlag }
569 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
570 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
571 this.modalService.closeCurrentModal();
575 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
576 'property': checkedInstanceProperty,
577 'componentInstanceMap': this.componentInstanceMap
579 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
580 disableSaveButtonFlag = !validationEvent.isValid;
582 modal.instance.open();
585 private clearCheckedInstancePropertyValue() {
586 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
587 const currentValue : any = checkedInstanceProperty.value;
588 checkedInstanceProperty.getInputValues = null;
589 checkedInstanceProperty.value = null;
590 checkedInstanceProperty.toscaFunction = null;
591 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
592 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
593 const parts = propertiesNameArray.split("#");
595 if (this.isListOrMap(checkedInstanceProperty.type)) {
596 if (checkedInstanceProperty.schemaType == PROPERTY_TYPES.MAP) {
597 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).parentMapKey);
599 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).mapKey);
600 if (checkedInstanceProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedInstanceProperty.schemaType)) {
601 currentKey.push(parts.reverse()[0]);
604 if (propertiesNameArray.length > 1){
605 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
606 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
608 if(currentValue !== null && currentKey.length > 0){
609 let valueJson = JSON.parse(currentValue);
610 if(currentKey.length >1){
611 let innerObj = valueJson[currentKey[0]];
612 delete innerObj[currentKey[1]];
613 valueJson[currentKey[0]] = innerObj;
615 delete valueJson[currentKey[0]];
617 if (checkedInstanceProperty.type == PROPERTY_TYPES.LIST && currentKey.length == 1) {
618 let listValue = valueJson.filter(function (item) {
619 return item != null && item != '';
621 checkedInstanceProperty.value = JSON.stringify(listValue);
623 checkedInstanceProperty.value = JSON.stringify(valueJson);
627 if (this.selectedInstanceData instanceof ComponentInstance) {
628 this.updateInstanceProperty(checkedInstanceProperty);
629 } else if (this.selectedInstanceData instanceof GroupInstance) {
630 this.updateGroupInstanceProperty(checkedInstanceProperty);
631 } else if (this.selectedInstanceData instanceof PolicyInstance) {
632 this.updatePolicyInstanceProperty(checkedInstanceProperty);
636 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
637 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
638 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
639 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
640 const parts = propertiesName.split("#");
642 if (this.isListOrMap(checkedProperty.type)) {
643 if (checkedProperty.schemaType == PROPERTY_TYPES.MAP) {
644 currentKey.push((<DerivedFEProperty>checkedProperty.input).parentMapKey);
646 currentKey.push((<DerivedFEProperty>checkedProperty.input).mapKey);
647 if (checkedProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedProperty.schemaType)) {
648 currentKey.push(parts.reverse()[0]);
651 if (checkedProperty.subPropertyToscaFunctions == null){
652 checkedProperty.subPropertyToscaFunctions = [];
654 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
655 if (!subPropertyToscaFunction){
656 subPropertyToscaFunction = new SubPropertyToscaFunction();
657 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
659 subPropertyToscaFunction.toscaFunction = toscaFunction;
660 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
663 checkedProperty.subPropertyToscaFunctions = null;
664 checkedProperty.toscaFunction = toscaFunction;
666 if (this.selectedInstanceData instanceof ComponentInstance) {
667 this.updateInstanceProperty(checkedProperty);
668 } else if (this.selectedInstanceData instanceof GroupInstance) {
669 this.updateGroupInstanceProperty(checkedProperty);
670 } else if (this.selectedInstanceData instanceof PolicyInstance) {
671 this.updatePolicyInstanceProperty(checkedProperty);
675 private isComplexSchemaType(propertyType: string): boolean {
676 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
679 private isListOrMap(propertyType: string): boolean {
680 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
683 private areEqual(array1: string[], array2: string[]): boolean {
684 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
687 updateInstanceProperty(instanceProperty: PropertyBEModel) {
688 this.loadingProperties = true;
689 this.enableToscaFunction = false;
690 this.checkedToscaCount = 0;
691 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
692 this.selectedInstanceData.uniqueId, [instanceProperty])
694 this.changeSelectedInstance(this.getSelectedInstance());
696 this.loadingProperties = false;
697 console.error(error);
699 this.loadingProperties = false;
703 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
704 this.loadingProperties = true;
705 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
706 this.selectedInstanceData.uniqueId, [instanceProperty])
708 this.changeSelectedInstance(this.getSelectedInstance());
710 this.loadingProperties = false;
711 console.error(error);
713 this.loadingProperties = false;
717 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
718 this.loadingProperties = true;
719 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
720 this.selectedInstanceData.uniqueId, [instanceProperty])
722 this.changeSelectedInstance(this.getSelectedInstance());
724 this.loadingProperties = false;
725 console.error(error);
727 this.loadingProperties = false;
731 /*** DECLARE PROPERTIES/INPUTS ***/
732 declareInputFromProperties = (inputName:string): void => {
733 console.debug("==>" + this.constructor.name + ": declareProperties");
735 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
736 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
737 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
738 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
739 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
741 angular.forEach(instancesIds, (instanceId: string): void => {
742 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
743 if (selectedInstanceData instanceof ComponentInstance) {
744 if (!this.isInput(selectedInstanceData.originType)) {
745 // convert Property FE model -> Property BE model, extract only checked
746 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
748 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
751 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
753 } else if (selectedInstanceData instanceof GroupInstance) {
754 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
755 } else if (selectedInstanceData instanceof PolicyInstance) {
756 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
760 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
762 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
763 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
764 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
766 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
767 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
770 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
771 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
772 prop => !this.isCapabilityProperty(prop)
774 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
775 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
778 let isCapabilityPropertyChanged = false;
780 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
781 (prop: PropertyBEModel) => {
782 prop.name = prop.origName || prop.name;
783 if (this.isCapabilityProperty(prop)) {
784 isCapabilityPropertyChanged = true;
788 this.topologyTemplateService
789 .createInput(this.component, inputsToCreate, this.isSelf())
790 .subscribe((response) => {
791 this.selectInstanceRow(SERVICE_SELF_TITLE);
792 this.onInstanceSelectedUpdate(this.instances[0]);
793 this.setInputTabIndication(response.length);
794 this.checkedPropertiesCount = 0;
795 this.checkedChildPropertiesCount = 0;
796 _.forEach(response, (input: InputBEModel) => {
797 const newInput: InputFEModel = new InputFEModel(input);
798 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
799 this.inputs.push(newInput);
800 this.updatePropertyValueAfterDeclare(newInput);
802 if (isCapabilityPropertyChanged) {
803 this.reloadInstanceCapabilities();
805 }, error => {}); //ignore error
808 private openAddInputNameAndDeclareInputModal = (): void => {
809 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
810 const modalButtons = [];
811 const modal = this.modalService.createCustomModal(new ModalModel(
818 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
820 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
822 this.declareInputFromProperties(inputName);
824 this.notification.warning({
825 message: 'Failed to set input name',
829 this.modalService.closeCurrentModal();
832 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
833 this.modalService.closeCurrentModal();
835 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {});
836 modal.instance.open();
839 declareListProperties = (): void => {
840 // get selected properties
841 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
842 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
843 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
844 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
845 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
846 let propertyNameList: Array<string> = [];
849 angular.forEach(instancesIds, (instanceId: string): void => {
851 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
852 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
854 if (selectedInstanceData instanceof ComponentInstance) {
855 if (!this.isInput(selectedInstanceData.originType)) {
856 // convert Property FE model -> Property BE model, extract only checked
857 selectedComponentInstancesProperties[instanceId] = checkedProperties;
859 selectedComponentInstancesInputs[instanceId] = checkedProperties;
861 } else if (selectedInstanceData instanceof GroupInstance) {
862 selectedGroupInstancesProperties[instanceId] = checkedProperties;
863 } else if (selectedInstanceData instanceof PolicyInstance) {
864 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
867 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
868 propertyNameList.push(property.name);
872 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
874 let modalTitle = 'Declare Properties as List Input';
875 const modal = this.modalService.createCustomModal(new ModalModel(
877 modalTitle, /* title */
882 'blue', /* css class */
883 () => { /* callback */
884 let content:any = modal.instance.dynamicContent.instance;
887 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
888 let typelist: any = PROPERTY_TYPES.LIST;
889 let uniID: any = insId;
890 let boolfalse: any = false;
891 let required: any = content.propertyModel.required;
895 "type": content.propertyModel.simpleType,
899 let schemaProp :any = {
900 "type": content.propertyModel.simpleType,
904 reglistInput.description = content.propertyModel.description;
905 reglistInput.name = content.propertyModel.name;
906 reglistInput.type = typelist;
907 reglistInput.schemaType = content.propertyModel.simpleType;
908 reglistInput.instanceUniqueId = uniID;
909 reglistInput.uniqueId = uniID;
910 reglistInput.required = required;
911 reglistInput.schema = schem;
912 reglistInput.schemaProperty = schemaProp;
915 componentInstInputsMap: content.inputsToCreate,
916 listInput: reglistInput
919 this.topologyTemplateService
920 .createListInput(this.component, input, this.isSelf())
921 .subscribe(response => {
922 this.setInputTabIndication(response.length);
923 this.checkedPropertiesCount = 0;
924 this.checkedChildPropertiesCount = 0;
925 _.forEach(response, (input: InputBEModel) => {
926 let newInput: InputFEModel = new InputFEModel(input);
927 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
928 this.inputs.push(newInput);
929 // create list input does not return updated properties info, so need to reload
930 //this.updatePropertyValueAfterDeclare(newInput);
931 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
932 this.changeSelectedInstance(this.selectedInstanceData);
934 modal.instance.close();
936 }, error => {}); //ignore error
939 /*, getDisabled: function */
941 new ButtonModel('Cancel', 'outline grey', () => {
942 modal.instance.close();
947 // 3rd arg is passed to DeclareListComponent instance
948 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
949 modal.instance.open();
952 /*** DECLARE PROPERTIES/POLICIES ***/
953 declarePropertiesToPolicies = (): void => {
954 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
955 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
957 angular.forEach(instancesIds, (instanceId: string): void => {
958 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
959 if (selectedInstanceData instanceof ComponentInstance) {
960 if (!this.isInput(selectedInstanceData.originType)) {
961 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
966 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
967 this.loadingPolicies = true;
969 this.topologyTemplateService
970 .createPolicy(this.component, policiesToCreate, this.isSelf())
971 .subscribe(response => {
972 this.setPolicyTabIndication(response.length);
973 this.checkedPropertiesCount = 0;
974 this.displayPoliciesAsDeclared(response);
975 this.loadingPolicies = false;
980 displayPoliciesAsDeclared = (policies) => {
981 _.forEach(policies, (policy: any) => {
982 let newPolicy: InputFEModel = new InputFEModel(policy);
983 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
984 newPolicy.relatedPropertyName = policy.name;
985 newPolicy.relatedPropertyValue = policy.value;
986 this.updatePropertyValueAfterDeclare(newPolicy);
987 this.policies.push(policy);
991 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
992 return new Promise((resolve, reject) => {
993 if (!this.isValidChangedData) {
994 reject('Changed data is invalid - cannot save!');
997 if (!this.changedData.length) {
1002 // make request and its handlers
1004 let handleSuccess, handleError;
1005 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1006 if (this.isPropertiesTabSelected) {
1007 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1008 changedProp = <PropertyFEModel>changedProp;
1009 const propBE = new PropertyBEModel(changedProp);
1010 propBE.toscaPresentation = new ToscaPresentationData();
1011 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1012 propBE.value = changedProp.getJSONValue();
1013 propBE.name = changedProp.origName || changedProp.name;
1014 delete propBE.origName;
1017 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1019 if (this.selectedInstanceData instanceof ComponentInstance) {
1020 if (this.isInput(this.selectedInstanceData.originType)) {
1021 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1022 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1023 request = Observable.forkJoin(
1024 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1025 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1026 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1029 else if (changedInputsProperties.length) {
1030 request = this.componentInstanceServiceNg2
1031 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1033 else if (changedCapabilitiesProperties.length) {
1034 request = this.componentInstanceServiceNg2
1035 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1037 handleSuccess = (response) => {
1038 // reset each changed property with new value and remove it from changed properties list
1039 response.forEach((resInput) => {
1040 const changedProp = <PropertyFEModel>this.changedData.shift();
1041 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1045 if (this.isSelf()) {
1046 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1047 delete cp.constraints;
1051 request = this.componentInstanceServiceNg2
1052 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1054 handleSuccess = (response) => {
1055 // reset each changed property with new value and remove it from changed properties list
1056 response.forEach((resProp) => {
1057 const changedProp = <PropertyFEModel>this.changedData.shift();
1058 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1063 } else if (this.selectedInstanceData instanceof GroupInstance) {
1064 request = this.componentInstanceServiceNg2
1065 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1066 handleSuccess = (response) => {
1067 // reset each changed property with new value and remove it from changed properties list
1068 response.forEach((resProp) => {
1069 const changedProp = <PropertyFEModel>this.changedData.shift();
1070 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1074 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1075 request = this.componentInstanceServiceNg2
1076 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1077 handleSuccess = (response) => {
1078 // reset each changed property with new value and remove it from changed properties list
1079 response.forEach((resProp) => {
1080 const changedProp = <PropertyFEModel>this.changedData.shift();
1081 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1086 } else if (this.isInputsTabSelected) {
1088 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1089 changedInput = <InputFEModel>changedInput;
1090 const inputBE = new InputBEModel(changedInput);
1091 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1094 request = this.componentServiceNg2
1095 .updateComponentInputs(this.component, changedInputs);
1096 handleSuccess = (response) => {
1097 // reset each changed property with new value and remove it from changed properties list
1098 response.forEach((resInput) => {
1099 const changedInput = <InputFEModel>this.changedData.shift();
1100 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1101 changedInput.required = resInput.required;
1102 changedInput.requiredOrig = resInput.required;
1107 this.savingChangedData = true;
1110 this.savingChangedData = false;
1111 if (changedCapabilitiesProperties.length) {
1112 this.reloadInstanceCapabilities();
1114 handleSuccess && handleSuccess(response);
1115 this.updateHasChangedData();
1119 this.savingChangedData = false;
1120 handleError && handleError(error);
1121 this.updateHasChangedData();
1128 reloadInstanceCapabilities = (): void => {
1129 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1130 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1131 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1132 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1133 return instance.capabilities;
1136 }, new CapabilitiesGroup());
1137 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1141 reverseChangedData = ():void => {
1142 // make reverse item handler
1143 let handleReverseItem;
1144 if (this.isPropertiesTabSelected) {
1145 handleReverseItem = (changedItem) => {
1146 changedItem = <PropertyFEModel>changedItem;
1147 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1149 } else if (this.isInputsTabSelected) {
1150 handleReverseItem = (changedItem) => {
1151 changedItem = <InputFEModel>changedItem;
1152 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1153 changedItem.resetMetadata();
1154 changedItem.required = changedItem.requiredOrig;
1158 this.changedData.forEach(handleReverseItem);
1159 this.changedData = [];
1160 this.updateHasChangedData();
1163 updateHasChangedData = ():boolean => {
1164 const curHasChangedData:boolean = (this.changedData.length > 0);
1165 if (curHasChangedData !== this.hasChangedData) {
1166 this.hasChangedData = curHasChangedData;
1167 if(this.hasChangedData) {
1168 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1170 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1173 return this.hasChangedData;
1176 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1177 this.saveChangedData().then(
1179 this.notification.success({
1180 message: 'Successfully saved changes',
1183 if(onSuccessFunction) onSuccessFunction();
1186 this.notification.error({
1187 message: 'Failed to save changes!',
1190 if(onError) onError();
1195 showUnsavedChangesAlert = ():Promise<any> => {
1196 let modalTitle:string;
1197 if (this.isPropertiesTabSelected) {
1198 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1199 } else if (this.isInputsTabSelected) {
1200 modalTitle = `Unsaved inputs for ${this.component.name}`;
1203 return new Promise<any>((resolve, reject) => {
1204 const modal = this.ModalServiceSdcUI.openCustomModal(
1208 type: SdcUiCommon.ModalType.custom,
1209 testId: "navigate-modal",
1212 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1213 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1214 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1215 ] as SdcUiCommon.IModalButtonComponent[]
1216 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1221 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1222 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1223 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1224 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1225 return feProperty.name == input.relatedPropertyName &&
1226 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1228 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1229 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1230 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1231 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1235 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1236 updateCheckedPropertyCount = (increment: boolean): void => {
1237 this.checkedPropertiesCount += (increment) ? 1 : -1;
1238 this.checkedToscaCount = 0;
1239 this.enableToscaFunction = false;
1240 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1243 updateCheckedChildPropertyCount = (increment: boolean): void => {
1244 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1247 togggleToscaBtn = (toscaFlag: boolean) : void => {
1248 this.checkedToscaCount += toscaFlag ? 1 : -1;
1249 if(this.checkedToscaCount == 1){
1250 this.enableToscaFunction = true;
1252 this.enableToscaFunction = false;
1256 setInputTabIndication = (numInputs: number): void => {
1257 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1260 setPolicyTabIndication = (numPolicies: number): void => {
1261 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1264 resetUnsavedChangesForInput = (input:InputFEModel) => {
1265 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1266 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1267 this.updateHasChangedData();
1270 deleteInput = (input: InputFEModel) => {
1271 //reset any unsaved changes to the input before deleting it
1272 this.resetUnsavedChangesForInput(input);
1274 console.debug("==>" + this.constructor.name + ": deleteInput");
1275 let inputToDelete = new InputBEModel(input);
1277 this.componentServiceNg2
1278 .deleteInput(this.component, inputToDelete)
1279 .subscribe(response => {
1280 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1282 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1283 this.changeSelectedInstance(this.selectedInstanceData);
1284 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1286 // if (instanceFeProperties) {
1287 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1288 // return prop.name == input.propertyName;
1291 // if (propToEnable) {
1292 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1293 // propToEnable.setNonDeclared(response.inputPath);
1294 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1295 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1298 }, error => {}); //ignore error
1301 deletePolicy = (policy: PolicyInstance) => {
1302 this.loadingPolicies = true;
1303 this.topologyTemplateService
1304 .deletePolicy(this.component, policy)
1305 .subscribe((response) => {
1306 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1307 this.changeSelectedInstance(this.selectedInstanceData);
1308 this.loadingPolicies = false;
1312 deleteProperty = (property: PropertyFEModel) => {
1313 const propertyToDelete = new PropertyFEModel(property);
1314 this.loadingProperties = true;
1315 const feMap = this.instanceFePropertiesMap;
1316 this.topologyTemplateService
1317 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1318 .subscribe((response) => {
1319 const props = feMap[this.component.uniqueId];
1320 props.splice(props.findIndex(p => p.uniqueId === response),1);
1321 this.loadingProperties = false;
1323 this.loadingProperties = false;
1324 console.error(error);
1328 /*** addProperty ***/
1329 addProperty = (model: string) => {
1330 this.loadDataTypesByComponentModel(model)
1331 let modalTitle = 'Add Property';
1332 let modal = this.modalService.createCustomModal(new ModalModel(
1337 new ButtonModel('Save', 'blue', () => {
1338 modal.instance.dynamicContent.instance.isLoading = true;
1339 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1340 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1341 .subscribe((response) => {
1342 modal.instance.dynamicContent.instance.isLoading = false;
1343 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1344 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1345 modal.instance.close();
1347 modal.instance.dynamicContent.instance.isLoading = false;
1348 this.notification.error({
1349 message: 'Failed to add property:' + error,
1353 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1354 new ButtonModel('Cancel', 'outline grey', () => {
1355 modal.instance.close();
1360 modal.instance.open();
1361 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1366 let modalTitle = 'Add Input';
1367 let modal = this.modalService.createCustomModal(new ModalModel(
1372 new ButtonModel('Save', 'blue', () => {
1373 modal.instance.dynamicContent.instance.isLoading = true;
1374 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1375 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1376 .subscribe((response) => {
1377 modal.instance.dynamicContent.instance.isLoading = false;
1378 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1379 this.inputs.push(newInputProp);
1380 modal.instance.close();
1382 modal.instance.dynamicContent.instance.isLoading = false;
1383 this.notification.error({
1384 message: 'Failed to add input:' + error,
1388 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1389 new ButtonModel('Cancel', 'outline grey', () => {
1390 modal.instance.close();
1395 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1396 modal.instance.open();
1399 /*** SEARCH RELATED FUNCTIONS ***/
1400 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1401 let instanceBePropertiesMap:InstanceBePropertiesMap;
1402 this.componentServiceNg2
1403 .filterComponentInstanceProperties(this.component, filterData)
1404 .subscribe((response) => {
1405 this.processInstancePropertiesResponse(response, false);
1406 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1407 this.searchPropertyName = filterData.propertyName;//mark in table
1408 this.hierarchyNavTabs.triggerTabChange('Composition');
1409 this.propertiesNavigationData = [];
1410 this.displayClearSearch = true;
1411 }, (error) => {}); //ignore error
1415 clearSearch = () => {
1416 this.instancesNavigationData = this.instances;
1417 this.searchPropertyName = "";
1418 this.hierarchyPropertiesDisplayOptions.searchText = "";
1419 this.displayClearSearch = false;
1420 this.advanceSearch.clearAll();
1421 this.searchQuery = '';
1424 clickOnClearSearch = () => {
1426 this.selectFirstInstanceByDefault();
1427 this.hierarchyNavTabs.triggerTabChange('Composition');
1430 private isInput = (instanceType:string):boolean =>{
1431 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1434 loadDataTypesByComponentModel(model:string) {
1435 this.propertyCreatorComponent.filterDataTypesByModel(model);