2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 import * as _ from "lodash";
22 import {Component, Inject, ViewChild} from "@angular/core";
23 import {PropertiesService} from "../../services/properties.service";
26 Component as ComponentData,
29 FilterPropertiesAssignmentData,
33 InstanceBePropertiesMap,
34 InstanceFePropertiesMap,
35 InstancePropertiesAPIMap,
42 PropertyDeclareAPIModel,
45 import {ResourceType} from "app/utils";
46 import {ComponentServiceNg2} from "../../services/component-services/component.service";
47 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
48 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
49 import {KeysPipe} from 'app/ng2/pipes/keys.pipe';
50 import {EVENTS, PROPERTY_TYPES, WorkspaceMode, PROPERTY_DATA} from "../../../utils/constants";
51 import {EventListenerService} from "app/services/event-listener-service"
52 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
53 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
54 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
55 import {HierarchyNavService} from "./services/hierarchy-nav.service";
56 import {PropertiesUtils} from "./services/properties.utils";
57 import {ComponentModeService} from "../../services/component-services/component-mode.service";
58 import {Tab, Tabs} from "../../components/ui/tabs/tabs.component";
59 import {InputsUtils} from "./services/inputs.utils";
60 import {InstanceFeDetails} from "../../../models/instance-fe-details";
61 import {SdcUiCommon, SdcUiServices} from "onap-ui-angular";
62 import {UnsavedChangesComponent} from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
63 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
64 import {ModalService} from "../../services/modal.service";
65 import {DeclareListComponent} from "./declare-list/declare-list.component";
66 import {ToscaFunctionComponent, ToscaFunctionValidationEvent} from "./tosca-function/tosca-function.component";
67 import {CapabilitiesGroup, Capability} from "../../../models/capability";
68 import {ToscaPresentationData} from "../../../models/tosca-presentation";
69 import {Observable} from "rxjs";
70 import {TranslateService} from "../../shared/translator/translate.service";
71 import {ToscaFunction} from "../../../models/tosca-function";
72 import {SubPropertyToscaFunction} from "../../../models/sub-property-tosca-function";
73 import {DeclareInputComponent} from "./declare-input/declare-input.component";
75 const SERVICE_SELF_TITLE = "SELF";
77 templateUrl: './properties-assignment.page.component.html',
78 styleUrls: ['./properties-assignment.page.component.less']
80 export class PropertiesAssignmentComponent {
81 title = "Properties & Inputs";
83 component: ComponentData;
84 componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
85 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
87 propertiesNavigationData = [];
88 instancesNavigationData = [];
90 instanceFePropertiesMap: InstanceFePropertiesMap;
91 inputs: Array<InputFEModel> = [];
92 policies: Array<PolicyInstance> = [];
93 instances: Array<ComponentInstance | GroupInstance | PolicyInstance> = [];
95 propertyStructureHeader: string;
97 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
98 selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = null;
99 checkedPropertiesCount: number = 0;
100 checkedChildPropertiesCount: number = 0;
101 enableToscaFunction: boolean = false;
102 checkedToscaCount: number = 0;
104 hierarchyPropertiesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
105 hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
106 displayClearSearch = false;
107 searchPropertyName: string;
109 isInputsTabSelected: boolean;
110 isPropertiesTabSelected: boolean;
111 isPoliciesTabSelected: boolean;
113 resourceIsReadonly: boolean;
114 loadingInstances: boolean = false;
115 loadingInputs: boolean = false;
116 loadingPolicies: boolean = false;
117 loadingProperties: boolean = false;
118 changedData: Array<PropertyFEModel | InputFEModel>;
119 hasChangedData: boolean;
120 isValidChangedData: boolean;
121 savingChangedData: boolean;
122 stateChangeStartUnregister: Function;
123 serviceBePropertiesMap: InstanceBePropertiesMap;
124 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
125 selectedInstance_FlattenCapabilitiesList: Capability[];
126 componentInstancePropertyMap : PropertiesGroup;
127 defaultInputName: string;
129 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
130 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
131 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
133 constructor(private propertiesService: PropertiesService,
134 private hierarchyNavService: HierarchyNavService,
135 private propertiesUtils: PropertiesUtils,
136 private inputsUtils: InputsUtils,
137 private componentServiceNg2: ComponentServiceNg2,
138 private componentInstanceServiceNg2: ComponentInstanceServiceNg2,
139 private propertyCreatorComponent: PropertyCreatorComponent,
140 @Inject("$stateParams") _stateParams,
141 @Inject("$scope") private $scope: ng.IScope,
142 @Inject("$state") private $state: ng.ui.IStateService,
143 @Inject("Notification") private notification: any,
144 private componentModeService: ComponentModeService,
145 private eventListenerService: EventListenerService,
146 private ModalServiceSdcUI: SdcUiServices.ModalService,
147 private modalService: ModalService,
148 private keysPipe: KeysPipe,
149 private topologyTemplateService: TopologyTemplateService,
150 private translateService: TranslateService) {
152 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
153 /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time
154 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
155 this.component = _stateParams.component;
156 this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
157 this.updateViewMode();
158 this.changedData = [];
159 this.updateHasChangedData();
160 this.isValidChangedData = true;
164 console.debug("==>" + this.constructor.name + ": ngOnInit");
165 this.loadingInputs = true;
166 this.loadingPolicies = true;
167 this.loadingInstances = true;
168 this.loadingProperties = true;
169 this.topologyTemplateService
170 .getComponentInputsWithProperties(this.component.componentType, this.component.uniqueId)
171 .subscribe(response => {
172 _.forEach(response.inputs, (input: InputBEModel) => {
173 const newInput: InputFEModel = new InputFEModel(input);
174 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
175 this.inputs.push(newInput); //only push items that were declared via SDC
177 this.componentInstancePropertyMap = response.componentInstancesProperties;
178 this.loadingInputs = false;
182 this.componentServiceNg2
183 .getComponentResourcePropertiesData(this.component)
184 .subscribe(response => {
185 this.loadingPolicies = false;
187 this.instances.push(...response.componentInstances);
188 this.instances.push(...response.groupInstances);
189 this.instances.push(...response.policies);
191 if (response.componentInstances) {
192 response.componentInstances.forEach(instance => {
193 this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
195 iconClass: instance.iconClass,
196 originArchived: instance.originArchived
201 _.forEach(response.policies, (policy: any) => {
202 const newPolicy: InputFEModel = new InputFEModel(policy);
203 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
204 this.policies.push(policy);
207 // add the service self instance to the top of the list.
208 const serviceInstance = new ComponentInstance();
209 serviceInstance.name = SERVICE_SELF_TITLE;
210 serviceInstance.uniqueId = this.component.uniqueId;
211 this.instances.unshift(serviceInstance);
213 _.forEach(this.instances, (instance) => {
214 this.instancesNavigationData.push(instance);
215 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{
217 iconClass: instance.iconClass,
218 originArchived: instance.originArchived
221 this.loadingInstances = false;
222 if (this.instancesNavigationData[0] == undefined) {
223 this.loadingProperties = false;
225 this.selectFirstInstanceByDefault();
227 this.loadingInstances = false;
230 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
231 // stop if has changed properties
232 if (this.hasChangedData) {
233 event.preventDefault();
234 this.showUnsavedChangesAlert().then(() => {
235 this.$state.go(toState, toParams);
241 this.loadDataTypesByComponentModel(this.component.model);
245 this.eventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
246 this.stateChangeStartUnregister();
249 selectFirstInstanceByDefault = () => {
250 if (this.instancesNavigationData[0] !== undefined) {
251 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
255 updateViewMode = () => {
256 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
259 onCheckout = (component: ComponentData) => {
260 this.component = component;
261 this.updateViewMode();
264 isSelf = (): boolean => {
265 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
268 showAddProperties = (): boolean => {
269 if (this.component.isService() && !(<Service>this.component).isSubstituteCandidate()) {
272 return this.isSelf();
275 getServiceProperties() {
276 this.loadingProperties = true;
277 this.topologyTemplateService
278 .getServiceProperties(this.component.uniqueId)
279 .subscribe((response) => {
280 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
281 this.serviceBePropertiesMap[this.component.uniqueId] = response;
282 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
283 this.loadingProperties = false;
285 this.loadingProperties = false;
289 onInstanceSelectedUpdate = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
290 // stop if has changed properties
291 if (this.hasChangedData) {
292 this.showUnsavedChangesAlert().then((resolve) => {
293 this.changeSelectedInstance(instance)
298 this.changeSelectedInstance(instance);
301 changeSelectedInstance = (instance: ComponentInstance | GroupInstance | PolicyInstance) => {
302 this.selectedInstanceData = instance;
303 this.loadingProperties = true;
304 if (instance instanceof ComponentInstance) {
305 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
306 if (this.isInput(instance.originType)) {
307 this.componentInstanceServiceNg2
308 .getComponentInstanceInputs(this.component, instance)
309 .subscribe(response => {
310 instanceBePropertiesMap[instance.uniqueId] = response;
311 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
315 this.loadingProperties = false;
317 } else if (this.isSelf()) {
318 this.getServiceProperties();
320 this.componentInstanceServiceNg2
321 .getComponentInstanceProperties(this.component, instance.uniqueId)
322 .subscribe(response => {
323 instanceBePropertiesMap[instance.uniqueId] = response;
324 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
328 this.loadingProperties = false;
331 this.loadingProperties = false;
332 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
333 } else if (instance instanceof GroupInstance) {
334 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
335 this.componentInstanceServiceNg2
336 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
337 .subscribe((response) => {
338 instanceBePropertiesMap[instance.uniqueId] = response;
339 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
343 this.loadingProperties = false;
345 } else if (instance instanceof PolicyInstance) {
346 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
347 this.componentInstanceServiceNg2
348 .getComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId)
349 .subscribe((response) => {
350 instanceBePropertiesMap[instance.uniqueId] = response;
351 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
355 this.loadingProperties = false;
358 this.loadingProperties = false;
361 if (this.searchPropertyName) {
364 //clear selected property from the navigation
365 this.selectedFlatProperty = new SimpleFlatProperty();
366 this.propertiesNavigationData = [];
370 * Entry point handling response from server
372 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
373 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs, this.component.model); //create flattened children, disable declared props, and init values
374 this.checkedPropertiesCount = 0;
375 this.checkedChildPropertiesCount = 0;
378 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
379 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
380 let currentUniqueId = this.selectedInstanceData.uniqueId;
381 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
382 let isCapabilityOwnedByInstance: boolean;
383 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
384 this.selectedInstance_FlattenCapabilitiesList,
385 (result, cap: Capability) => {
386 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
387 selectedComponentInstanceData.isServiceProxy() || selectedComponentInstanceData.isServiceSubstitution() &&
388 cap.ownerId === selectedComponentInstanceData.sourceModelUid;
389 if (cap.properties && isCapabilityOwnedByInstance) {
390 _.forEach(cap.properties, prop => {
391 if (!prop.origName) {
392 prop.origName = prop.name;
393 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
396 return result.concat(cap.properties);
400 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
401 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
402 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
403 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
405 //concatenate capabilitiesProps to all props list
406 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
407 this.checkedPropertiesCount = 0;
410 isCapabilityProperty = (prop: PropertyBEModel) => {
411 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
414 /*** VALUE CHANGE EVENTS ***/
415 dataChanged = (item: PropertyFEModel | InputFEModel) => {
417 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
418 itemHasChanged = item.hasValueObjChanged();
419 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
420 itemHasChanged = item.hasChanged();
421 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
422 itemHasChanged = item.hasDefaultValueChanged();
425 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
426 if (itemHasChanged) {
427 if (dataChangedIdx === -1) {
428 this.changedData.push(item);
431 if (dataChangedIdx !== -1) {
432 this.changedData.splice(dataChangedIdx, 1);
436 if (this.isPropertiesTabSelected) {
437 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
438 } else if (this.isInputsTabSelected) {
439 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
440 } else if (this.isPoliciesTabSelected) {
441 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
443 this.updateHasChangedData();
447 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
450 * Handle select node in navigation area, and select the row in table
452 onPropertySelectedUpdate = ($event) => {
453 console.debug("==>" + this.constructor.name + ": onPropertySelectedUpdate");
454 this.selectedFlatProperty = $event;
455 let parentProperty: PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
456 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
460 * When user select row in table, this will prepare the hirarchy object for the tree.
462 selectPropertyRow = (propertyRowSelectedEvent: PropertyRowSelectedEvent) => {
463 console.debug("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
464 let property = propertyRowSelectedEvent.propertyModel;
465 let instanceName = propertyRowSelectedEvent.instanceName;
466 this.propertyStructureHeader = null;
468 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
469 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
470 let simpleFlatProperty: Array<SimpleFlatProperty>;
471 if (property instanceof PropertyFEModel) {
472 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
473 } else if (property instanceof DerivedFEProperty) {
474 // Need to find parent PropertyFEModel
475 let parentPropertyFEModel: PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty): boolean => {
476 return property.propertiesName.indexOf(tmpFeProperty.name) === 0;
478 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
480 this.propertiesNavigationData = simpleFlatProperty;
483 // Update the header in the navigation tree with property name.
484 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
486 // Set selected property in table
487 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
488 this.hierarchyNavTabs.triggerTabChange('Property Structure');
492 selectInstanceRow = ($event) => {//get instance name
493 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance: ComponentInstance) => {
494 return instance.name == $event;
496 this.hierarchyNavTabs.triggerTabChange('Composition');
499 tabChanged = (event) => {
500 // stop if has changed properties
501 if (this.hasChangedData) {
502 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
503 this.showUnsavedChangesAlert().then((proceed) => {
504 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
510 console.debug("==>" + this.constructor.name + ": tabChanged " + event);
511 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
512 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
513 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
514 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
515 this.propertyStructureHeader = null;
516 this.searchQuery = '';
520 * Select Tosca function value from defined values
522 selectToscaFunctionAndValues = (): void => {
523 const selectedInstanceData: ComponentInstance | GroupInstance | PolicyInstance = this.getSelectedInstance();
524 if (!selectedInstanceData) {
527 this.openToscaGetFunctionModal();
530 private getSelectedInstance(): ComponentInstance | GroupInstance | PolicyInstance {
531 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
532 const instanceId: string = instancesIds[0];
533 return <ComponentInstance | GroupInstance | PolicyInstance> this.instances.find(instance =>
534 instance.uniqueId == instanceId && (instance instanceof ComponentInstance || instance instanceof GroupInstance || instance instanceof PolicyInstance));
537 private buildCheckedInstanceProperty(): PropertyBEModel {
538 return this.buildCheckedInstanceProperties()[0];
541 private buildCheckedInstanceProperties(): PropertyBEModel[] {
542 const instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
543 const instanceId: string = instancesIds[0];
544 return this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
547 private openToscaGetFunctionModal() {
548 const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
549 const modalButtons = [];
550 let disableSaveButtonFlag = true;
551 const modal = this.modalService.createCustomModal(new ModalModel(
558 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
560 const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
561 if (toscaGetFunction) {
562 this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
564 this.clearCheckedInstancePropertyValue();
566 this.modalService.closeCurrentModal();
568 (): boolean => { return disableSaveButtonFlag }
570 const checkedInstanceProperty = this.buildCheckedInstanceProperty();
571 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
572 this.modalService.closeCurrentModal();
576 this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
577 'property': checkedInstanceProperty,
578 'componentInstanceMap': this.componentInstanceMap
580 modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
581 disableSaveButtonFlag = !validationEvent.isValid;
583 modal.instance.open();
586 private clearCheckedInstancePropertyValue() {
587 const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
588 const currentValue : any = checkedInstanceProperty.value;
589 checkedInstanceProperty.getInputValues = null;
590 checkedInstanceProperty.value = null;
591 checkedInstanceProperty.toscaFunction = null;
592 if (checkedInstanceProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName){
593 const propertiesNameArray = (<PropertyDeclareAPIModel>checkedInstanceProperty).propertiesName;
594 const parts = propertiesNameArray.split("#");
596 if (this.isListOrMap(checkedInstanceProperty.type)) {
597 if (checkedInstanceProperty.schemaType == PROPERTY_TYPES.MAP) {
598 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).parentMapKey);
600 currentKey.push((<DerivedFEProperty>checkedInstanceProperty.input).mapKey);
601 if (checkedInstanceProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedInstanceProperty.schemaType)) {
602 currentKey.push(parts.reverse()[0]);
605 if (propertiesNameArray.length > 1){
606 const index = checkedInstanceProperty.subPropertyToscaFunctions.findIndex(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
607 checkedInstanceProperty.subPropertyToscaFunctions.splice(index, 1);
609 if(currentValue !== null && currentKey.length > 0){
610 let valueJson = JSON.parse(currentValue);
611 if(currentKey.length >1){
612 let innerObj = valueJson[currentKey[0]];
613 delete innerObj[currentKey[1]];
614 valueJson[currentKey[0]] = innerObj;
616 delete valueJson[currentKey[0]];
618 if (checkedInstanceProperty.type == PROPERTY_TYPES.LIST && currentKey.length == 1) {
619 let listValue = valueJson.filter(function (item) {
620 return item != null && item != '';
622 checkedInstanceProperty.value = JSON.stringify(listValue);
624 checkedInstanceProperty.value = JSON.stringify(valueJson);
628 if (this.selectedInstanceData instanceof ComponentInstance) {
629 this.updateInstanceProperty(checkedInstanceProperty);
630 } else if (this.selectedInstanceData instanceof GroupInstance) {
631 this.updateGroupInstanceProperty(checkedInstanceProperty);
632 } else if (this.selectedInstanceData instanceof PolicyInstance) {
633 this.updatePolicyInstanceProperty(checkedInstanceProperty);
637 private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
638 const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
639 if (checkedProperty instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>checkedProperty).propertiesName){
640 const propertiesName = (<PropertyDeclareAPIModel>checkedProperty).propertiesName;
641 const parts = propertiesName.split("#");
643 if (this.isListOrMap(checkedProperty.type)) {
644 if (checkedProperty.schemaType == PROPERTY_TYPES.MAP) {
645 currentKey.push((<DerivedFEProperty>checkedProperty.input).parentMapKey);
647 currentKey.push((<DerivedFEProperty>checkedProperty.input).mapKey);
648 if (checkedProperty.schemaType != PROPERTY_TYPES.MAP && this.isComplexSchemaType(checkedProperty.schemaType)) {
649 currentKey.push(parts.reverse()[0]);
652 if (checkedProperty.subPropertyToscaFunctions == null){
653 checkedProperty.subPropertyToscaFunctions = [];
655 let subPropertyToscaFunction = checkedProperty.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => this.areEqual(existingSubPropertyToscaFunction.subPropertyPath, currentKey.length > 0 ? currentKey : parts.slice(1)));
656 if (!subPropertyToscaFunction){
657 subPropertyToscaFunction = new SubPropertyToscaFunction();
658 checkedProperty.subPropertyToscaFunctions.push(subPropertyToscaFunction);
660 subPropertyToscaFunction.toscaFunction = toscaFunction;
661 subPropertyToscaFunction.subPropertyPath = currentKey.length > 0 ? currentKey : parts.slice(1);
664 checkedProperty.subPropertyToscaFunctions = null;
665 checkedProperty.toscaFunction = toscaFunction;
667 if (this.selectedInstanceData instanceof ComponentInstance) {
668 this.updateInstanceProperty(checkedProperty);
669 } else if (this.selectedInstanceData instanceof GroupInstance) {
670 this.updateGroupInstanceProperty(checkedProperty);
671 } else if (this.selectedInstanceData instanceof PolicyInstance) {
672 this.updatePolicyInstanceProperty(checkedProperty);
676 private isComplexSchemaType(propertyType: string): boolean {
677 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
680 private isListOrMap(propertyType: string): boolean {
681 return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
684 private areEqual(array1: string[], array2: string[]): boolean {
685 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
688 updateInstanceProperty(instanceProperty: PropertyBEModel) {
689 this.loadingProperties = true;
690 this.enableToscaFunction = false;
691 this.checkedToscaCount = 0;
692 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
693 this.selectedInstanceData.uniqueId, [instanceProperty])
695 this.changeSelectedInstance(this.getSelectedInstance());
697 this.loadingProperties = false;
698 console.error(error);
700 this.loadingProperties = false;
704 updateGroupInstanceProperty(instanceProperty: PropertyBEModel) {
705 this.loadingProperties = true;
706 this.componentInstanceServiceNg2.updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId,
707 this.selectedInstanceData.uniqueId, [instanceProperty])
709 this.changeSelectedInstance(this.getSelectedInstance());
711 this.loadingProperties = false;
712 console.error(error);
714 this.loadingProperties = false;
718 updatePolicyInstanceProperty(instanceProperty: PropertyBEModel) {
719 this.loadingProperties = true;
720 this.componentInstanceServiceNg2.updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId,
721 this.selectedInstanceData.uniqueId, [instanceProperty])
723 this.changeSelectedInstance(this.getSelectedInstance());
725 this.loadingProperties = false;
726 console.error(error);
728 this.loadingProperties = false;
732 /*** DECLARE PROPERTIES/INPUTS ***/
733 declareInputFromProperties = (inputName:string): void => {
734 console.debug("==>" + this.constructor.name + ": declareProperties");
736 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
737 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
738 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
739 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
740 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
742 angular.forEach(instancesIds, (instanceId: string): void => {
743 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
744 if (selectedInstanceData instanceof ComponentInstance) {
745 if (!this.isInput(selectedInstanceData.originType)) {
746 // convert Property FE model -> Property BE model, extract only checked
747 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
749 selectedComponentInstancesProperties[instanceId][0].inputName = inputName;
752 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
754 } else if (selectedInstanceData instanceof GroupInstance) {
755 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
756 } else if (selectedInstanceData instanceof PolicyInstance) {
757 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
761 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
763 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
764 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
765 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
767 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
768 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
771 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
772 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
773 prop => !this.isCapabilityProperty(prop)
775 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
776 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
779 let isCapabilityPropertyChanged = false;
781 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
782 (prop: PropertyBEModel) => {
783 prop.name = prop.origName || prop.name;
784 if (this.isCapabilityProperty(prop)) {
785 isCapabilityPropertyChanged = true;
789 this.topologyTemplateService
790 .createInput(this.component, inputsToCreate, this.isSelf())
791 .subscribe((response) => {
792 this.selectInstanceRow(SERVICE_SELF_TITLE);
793 this.onInstanceSelectedUpdate(this.instances[0]);
794 this.setInputTabIndication(response.length);
795 this.checkedPropertiesCount = 0;
796 this.checkedChildPropertiesCount = 0;
797 _.forEach(response, (input: InputBEModel) => {
798 const newInput: InputFEModel = new InputFEModel(input);
799 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
800 this.inputs.push(newInput);
801 this.updatePropertyValueAfterDeclare(newInput);
803 if (isCapabilityPropertyChanged) {
804 this.reloadInstanceCapabilities();
806 }, error => {}); //ignore error
809 generateDefaultInputName = (): string => {
810 let defaultInputName: string;
811 let instancesIds = this.keysPipe.transform(this.instanceFePropertiesMap, []);
812 angular.forEach(instancesIds, (instanceId: string) => {
813 let selectedProperty: PropertyBEModel = new PropertyBEModel(this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId])[0]);
814 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
815 defaultInputName = this.generateInputName(selectedInstanceData.invariantName, selectedProperty.name);
817 return defaultInputName;
820 private generateInputName = (componentName: string, propertyName: string): string => {
821 let inputName: string;
823 if (propertyName.includes("::")) {
824 propertyName = propertyName.replace("::", "_");
827 inputName = componentName + "_" + propertyName;
829 inputName = propertyName;
835 private openAddInputNameAndDeclareInputModal = (): void => {
836 const modalTitle = this.translateService.translate('ADD_INPUT_NAME_TO_DECLARE');
837 const modalButtons = [];
838 const modal = this.modalService.createCustomModal(new ModalModel(
845 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
847 const inputName: string = modal.instance.dynamicContent.instance.inputNameForm.value;
849 this.declareInputFromProperties(inputName);
851 this.notification.warning({
852 message: 'Failed to set input name',
856 this.modalService.closeCurrentModal();
859 modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
860 this.modalService.closeCurrentModal();
862 this.modalService.addDynamicContentToModal(modal, DeclareInputComponent, {defaultInputName: this.generateDefaultInputName()});
863 modal.instance.open();
866 declareListProperties = (): void => {
867 // get selected properties
868 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
869 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
870 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
871 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
872 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
873 let propertyNameList: Array<string> = [];
876 angular.forEach(instancesIds, (instanceId: string): void => {
878 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
879 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
881 if (selectedInstanceData instanceof ComponentInstance) {
882 if (!this.isInput(selectedInstanceData.originType)) {
883 // convert Property FE model -> Property BE model, extract only checked
884 selectedComponentInstancesProperties[instanceId] = checkedProperties;
886 selectedComponentInstancesInputs[instanceId] = checkedProperties;
888 } else if (selectedInstanceData instanceof GroupInstance) {
889 selectedGroupInstancesProperties[instanceId] = checkedProperties;
890 } else if (selectedInstanceData instanceof PolicyInstance) {
891 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
894 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
895 propertyNameList.push(property.name);
899 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
901 let modalTitle = 'Declare Properties as List Input';
902 const modal = this.modalService.createCustomModal(new ModalModel(
904 modalTitle, /* title */
909 'blue', /* css class */
910 () => { /* callback */
911 let content:any = modal.instance.dynamicContent.instance;
914 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
915 let typelist: any = PROPERTY_TYPES.LIST;
916 let uniID: any = insId;
917 let boolfalse: any = false;
918 let required: any = content.propertyModel.required;
922 "type": content.propertyModel.simpleType,
926 let schemaProp :any = {
927 "type": content.propertyModel.simpleType,
931 reglistInput.description = content.propertyModel.description;
932 reglistInput.name = content.propertyModel.name;
933 reglistInput.type = typelist;
934 reglistInput.schemaType = content.propertyModel.simpleType;
935 reglistInput.instanceUniqueId = uniID;
936 reglistInput.uniqueId = uniID;
937 reglistInput.required = required;
938 reglistInput.schema = schem;
939 reglistInput.schemaProperty = schemaProp;
942 componentInstInputsMap: content.inputsToCreate,
943 listInput: reglistInput
946 this.topologyTemplateService
947 .createListInput(this.component, input, this.isSelf())
948 .subscribe(response => {
949 this.setInputTabIndication(response.length);
950 this.checkedPropertiesCount = 0;
951 this.checkedChildPropertiesCount = 0;
952 _.forEach(response, (input: InputBEModel) => {
953 let newInput: InputFEModel = new InputFEModel(input);
954 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
955 this.inputs.push(newInput);
956 // create list input does not return updated properties info, so need to reload
957 //this.updatePropertyValueAfterDeclare(newInput);
958 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
959 this.changeSelectedInstance(this.selectedInstanceData);
961 modal.instance.close();
963 }, error => {}); //ignore error
966 /*, getDisabled: function */
968 new ButtonModel('Cancel', 'outline grey', () => {
969 modal.instance.close();
974 // 3rd arg is passed to DeclareListComponent instance
975 this.modalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
976 modal.instance.open();
979 /*** DECLARE PROPERTIES/POLICIES ***/
980 declarePropertiesToPolicies = (): void => {
981 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
982 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
984 angular.forEach(instancesIds, (instanceId: string): void => {
985 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
986 if (selectedInstanceData instanceof ComponentInstance) {
987 if (!this.isInput(selectedInstanceData.originType)) {
988 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
993 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
994 this.loadingPolicies = true;
996 this.topologyTemplateService
997 .createPolicy(this.component, policiesToCreate, this.isSelf())
998 .subscribe(response => {
999 this.setPolicyTabIndication(response.length);
1000 this.checkedPropertiesCount = 0;
1001 this.displayPoliciesAsDeclared(response);
1002 this.loadingPolicies = false;
1007 displayPoliciesAsDeclared = (policies) => {
1008 _.forEach(policies, (policy: any) => {
1009 let newPolicy: InputFEModel = new InputFEModel(policy);
1010 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
1011 newPolicy.relatedPropertyName = policy.name;
1012 newPolicy.relatedPropertyValue = policy.value;
1013 this.updatePropertyValueAfterDeclare(newPolicy);
1014 this.policies.push(policy);
1018 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
1019 return new Promise((resolve, reject) => {
1020 if (!this.isValidChangedData) {
1021 reject('Changed data is invalid - cannot save!');
1024 if (!this.changedData.length) {
1029 // make request and its handlers
1031 let handleSuccess, handleError;
1032 let changedInputsProperties = [], changedCapabilitiesProperties = [];
1033 if (this.isPropertiesTabSelected) {
1034 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
1035 changedProp = <PropertyFEModel>changedProp;
1036 const propBE = new PropertyBEModel(changedProp);
1037 propBE.toscaPresentation = new ToscaPresentationData();
1038 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
1039 propBE.value = changedProp.getJSONValue();
1040 propBE.name = changedProp.origName || changedProp.name;
1041 delete propBE.origName;
1044 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
1046 if (this.selectedInstanceData instanceof ComponentInstance) {
1047 if (this.isInput(this.selectedInstanceData.originType)) {
1048 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
1049 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
1050 request = Observable.forkJoin(
1051 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
1052 this.componentInstanceServiceNg2.updateInstanceProperties(this.component.componentType, this.component.uniqueId,
1053 this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
1056 else if (changedInputsProperties.length) {
1057 request = this.componentInstanceServiceNg2
1058 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
1060 else if (changedCapabilitiesProperties.length) {
1061 request = this.componentInstanceServiceNg2
1062 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
1064 handleSuccess = (response) => {
1065 // reset each changed property with new value and remove it from changed properties list
1066 response.forEach((resInput) => {
1067 const changedProp = <PropertyFEModel>this.changedData.shift();
1068 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
1072 if (this.isSelf()) {
1073 request = this.topologyTemplateService.updateServiceProperties(this.component.uniqueId, _.map(changedProperties, cp => {
1074 delete cp.constraints;
1078 request = this.componentInstanceServiceNg2
1079 .updateInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1081 handleSuccess = (response) => {
1082 // reset each changed property with new value and remove it from changed properties list
1083 response.forEach((resProp) => {
1084 const changedProp = <PropertyFEModel>this.changedData.shift();
1085 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1090 } else if (this.selectedInstanceData instanceof GroupInstance) {
1091 request = this.componentInstanceServiceNg2
1092 .updateComponentGroupInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1093 handleSuccess = (response) => {
1094 // reset each changed property with new value and remove it from changed properties list
1095 response.forEach((resProp) => {
1096 const changedProp = <PropertyFEModel>this.changedData.shift();
1097 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1101 } else if (this.selectedInstanceData instanceof PolicyInstance) {
1102 request = this.componentInstanceServiceNg2
1103 .updateComponentPolicyInstanceProperties(this.component.componentType, this.component.uniqueId, this.selectedInstanceData.uniqueId, changedProperties);
1104 handleSuccess = (response) => {
1105 // reset each changed property with new value and remove it from changed properties list
1106 response.forEach((resProp) => {
1107 const changedProp = <PropertyFEModel>this.changedData.shift();
1108 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
1113 } else if (this.isInputsTabSelected) {
1115 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
1116 changedInput = <InputFEModel>changedInput;
1117 const inputBE = new InputBEModel(changedInput);
1118 inputBE.defaultValue = changedInput.getJSONDefaultValue();
1121 request = this.componentServiceNg2
1122 .updateComponentInputs(this.component, changedInputs);
1123 handleSuccess = (response) => {
1124 // reset each changed property with new value and remove it from changed properties list
1125 response.forEach((resInput) => {
1126 const changedInput = <InputFEModel>this.changedData.shift();
1127 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
1128 changedInput.required = resInput.required;
1129 changedInput.requiredOrig = resInput.required;
1134 this.savingChangedData = true;
1137 this.savingChangedData = false;
1138 if (changedCapabilitiesProperties.length) {
1139 this.reloadInstanceCapabilities();
1141 handleSuccess && handleSuccess(response);
1142 this.updateHasChangedData();
1146 this.savingChangedData = false;
1147 handleError && handleError(error);
1148 this.updateHasChangedData();
1155 reloadInstanceCapabilities = (): void => {
1156 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
1157 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
1158 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
1159 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
1160 return instance.capabilities;
1163 }, new CapabilitiesGroup());
1164 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
1168 reverseChangedData = ():void => {
1169 // make reverse item handler
1170 let handleReverseItem;
1171 if (this.isPropertiesTabSelected) {
1172 handleReverseItem = (changedItem) => {
1173 changedItem = <PropertyFEModel>changedItem;
1174 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
1176 } else if (this.isInputsTabSelected) {
1177 handleReverseItem = (changedItem) => {
1178 changedItem = <InputFEModel>changedItem;
1179 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
1180 changedItem.resetMetadata();
1181 changedItem.required = changedItem.requiredOrig;
1185 this.changedData.forEach(handleReverseItem);
1186 this.changedData = [];
1187 this.updateHasChangedData();
1190 updateHasChangedData = ():boolean => {
1191 const curHasChangedData:boolean = (this.changedData.length > 0);
1192 if (curHasChangedData !== this.hasChangedData) {
1193 this.hasChangedData = curHasChangedData;
1194 if(this.hasChangedData) {
1195 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
1197 this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
1200 return this.hasChangedData;
1203 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
1204 this.saveChangedData().then(
1206 this.notification.success({
1207 message: 'Successfully saved changes',
1210 if(onSuccessFunction) onSuccessFunction();
1213 this.notification.error({
1214 message: 'Failed to save changes!',
1217 if(onError) onError();
1222 showUnsavedChangesAlert = ():Promise<any> => {
1223 let modalTitle:string;
1224 if (this.isPropertiesTabSelected) {
1225 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
1226 } else if (this.isInputsTabSelected) {
1227 modalTitle = `Unsaved inputs for ${this.component.name}`;
1230 return new Promise<any>((resolve, reject) => {
1231 const modal = this.ModalServiceSdcUI.openCustomModal(
1235 type: SdcUiCommon.ModalType.custom,
1236 testId: "navigate-modal",
1239 {id: 'cancelButton', text: 'Cancel', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => reject()},
1240 {id: 'discardButton', text: 'Discard', type: SdcUiCommon.ButtonType.secondary, size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
1241 {id: 'saveButton', text: 'Save', type: SdcUiCommon.ButtonType.primary, size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
1242 ] as SdcUiCommon.IModalButtonComponent[]
1243 } as SdcUiCommon.IModalConfig, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
1248 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
1249 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
1250 const instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
1251 const propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
1252 return feProperty.name == input.relatedPropertyName &&
1253 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
1255 const inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
1256 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
1257 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
1258 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
1262 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
1263 updateCheckedPropertyCount = (increment: boolean): void => {
1264 this.checkedPropertiesCount += (increment) ? 1 : -1;
1265 this.checkedToscaCount = 0;
1266 this.enableToscaFunction = false;
1267 console.debug("CheckedProperties count is now.... " + this.checkedPropertiesCount);
1270 updateCheckedChildPropertyCount = (increment: boolean): void => {
1271 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
1274 togggleToscaBtn = (toscaFlag: boolean) : void => {
1275 this.checkedToscaCount += toscaFlag ? 1 : -1;
1276 if(this.checkedToscaCount == 1){
1277 this.enableToscaFunction = true;
1279 this.enableToscaFunction = false;
1283 setInputTabIndication = (numInputs: number): void => {
1284 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
1287 setPolicyTabIndication = (numPolicies: number): void => {
1288 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
1291 resetUnsavedChangesForInput = (input:InputFEModel) => {
1292 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
1293 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
1294 this.updateHasChangedData();
1297 deleteInput = (input: InputFEModel) => {
1298 //reset any unsaved changes to the input before deleting it
1299 this.resetUnsavedChangesForInput(input);
1301 console.debug("==>" + this.constructor.name + ": deleteInput");
1302 let inputToDelete = new InputBEModel(input);
1304 this.componentServiceNg2
1305 .deleteInput(this.component, inputToDelete)
1306 .subscribe(response => {
1307 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
1309 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1310 this.changeSelectedInstance(this.selectedInstanceData);
1311 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
1313 // if (instanceFeProperties) {
1314 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
1315 // return prop.name == input.propertyName;
1318 // if (propToEnable) {
1319 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1320 // propToEnable.setNonDeclared(response.inputPath);
1321 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1322 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1325 }, error => {}); //ignore error
1328 deletePolicy = (policy: PolicyInstance) => {
1329 this.loadingPolicies = true;
1330 this.topologyTemplateService
1331 .deletePolicy(this.component, policy)
1332 .subscribe((response) => {
1333 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1334 this.changeSelectedInstance(this.selectedInstanceData);
1335 this.loadingPolicies = false;
1339 deleteProperty = (property: PropertyFEModel) => {
1340 const propertyToDelete = new PropertyFEModel(property);
1341 this.loadingProperties = true;
1342 const feMap = this.instanceFePropertiesMap;
1343 this.topologyTemplateService
1344 .deleteServiceProperty(this.component.uniqueId, propertyToDelete)
1345 .subscribe((response) => {
1346 const props = feMap[this.component.uniqueId];
1347 props.splice(props.findIndex(p => p.uniqueId === response),1);
1348 this.loadingProperties = false;
1350 this.loadingProperties = false;
1351 console.error(error);
1355 /*** addProperty ***/
1356 addProperty = (model: string) => {
1357 this.loadDataTypesByComponentModel(model)
1358 let modalTitle = 'Add Property';
1359 let modal = this.modalService.createCustomModal(new ModalModel(
1364 new ButtonModel('Save', 'blue', () => {
1365 modal.instance.dynamicContent.instance.isLoading = true;
1366 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1367 this.topologyTemplateService.createServiceProperty(this.component.uniqueId, newProperty)
1368 .subscribe((response) => {
1369 modal.instance.dynamicContent.instance.isLoading = false;
1370 const newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1371 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1372 modal.instance.close();
1374 modal.instance.dynamicContent.instance.isLoading = false;
1375 this.notification.error({
1376 message: 'Failed to add property:' + error,
1380 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1381 new ButtonModel('Cancel', 'outline grey', () => {
1382 modal.instance.close();
1387 modal.instance.open();
1388 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1393 let modalTitle = 'Add Input';
1394 let modal = this.modalService.createCustomModal(new ModalModel(
1399 new ButtonModel('Save', 'blue', () => {
1400 modal.instance.dynamicContent.instance.isLoading = true;
1401 const newInput: InputBEModel = modal.instance.dynamicContent.instance.propertyModel;
1402 this.topologyTemplateService.createServiceInput(this.component.uniqueId, newInput)
1403 .subscribe((response) => {
1404 modal.instance.dynamicContent.instance.isLoading = false;
1405 const newInputProp: InputFEModel = this.inputsUtils.convertInputBEToInputFE(response);
1406 this.inputs.push(newInputProp);
1407 modal.instance.close();
1409 modal.instance.dynamicContent.instance.isLoading = false;
1410 this.notification.error({
1411 message: 'Failed to add input:' + error,
1415 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1416 new ButtonModel('Cancel', 'outline grey', () => {
1417 modal.instance.close();
1422 this.modalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1423 modal.instance.open();
1426 /*** SEARCH RELATED FUNCTIONS ***/
1427 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1428 let instanceBePropertiesMap:InstanceBePropertiesMap;
1429 this.componentServiceNg2
1430 .filterComponentInstanceProperties(this.component, filterData)
1431 .subscribe((response) => {
1432 this.processInstancePropertiesResponse(response, false);
1433 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1434 this.searchPropertyName = filterData.propertyName;//mark in table
1435 this.hierarchyNavTabs.triggerTabChange('Composition');
1436 this.propertiesNavigationData = [];
1437 this.displayClearSearch = true;
1438 }, (error) => {}); //ignore error
1442 clearSearch = () => {
1443 this.instancesNavigationData = this.instances;
1444 this.searchPropertyName = "";
1445 this.hierarchyPropertiesDisplayOptions.searchText = "";
1446 this.displayClearSearch = false;
1447 this.advanceSearch.clearAll();
1448 this.searchQuery = '';
1451 clickOnClearSearch = () => {
1453 this.selectFirstInstanceByDefault();
1454 this.hierarchyNavTabs.triggerTabChange('Composition');
1457 private isInput = (instanceType:string):boolean =>{
1458 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;
1461 loadDataTypesByComponentModel(model:string) {
1462 this.propertyCreatorComponent.filterDataTypesByModel(model);