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, ViewChild, Inject, TemplateRef} from "@angular/core";
23 import { PropertiesService } from "../../services/properties.service";
26 InstanceFePropertiesMap,
27 InstanceBePropertiesMap,
28 InstancePropertiesAPIMap,
29 Component as ComponentData,
30 FilterPropertiesAssignmentData,
36 import { ResourceType } from "app/utils";
37 import {ComponentServiceNg2} from "../../services/component-services/component.service";
38 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
50 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
51 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
52 import {EventListenerService} from "app/services/event-listener-service"
53 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
54 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
55 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
56 import {HierarchyNavService} from "./services/hierarchy-nav.service";
57 import {PropertiesUtils} from "./services/properties.utils";
58 import {ComponentModeService} from "../../services/component-services/component-mode.service";
59 import {ModalService} from "../../services/modal.service";
60 import {Tabs, Tab} from "../../components/ui/tabs/tabs.component";
61 import {InputsUtils} from "./services/inputs.utils";
62 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
63 import {DeclareListComponent} from "./declare-list/declare-list.component";
64 import { InstanceFeDetails } from "../../../models/instance-fe-details";
65 import { SdcUiComponents } from "sdc-ui/lib/angular";
66 //import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service";
67 import { IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config";
68 import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
69 import {Observable} from "rxjs";
70 import { DataTypeService } from "app/ng2/services/data-type.service";
71 import { DataTypeModel } from "app/models";
72 import { PROPERTY_DATA, PROPERTY_TYPES } from "app/utils";
73 import { PropertyDeclareAPIModel} from "app/models";
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: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
86 propertiesNavigationData = [];
87 instancesNavigationData = [];
89 instanceFePropertiesMap:InstanceFePropertiesMap;
90 inputs: Array<InputFEModel> = [];
91 policies: Array<PolicyInstance> = [];
92 instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
94 propertyStructureHeader: string;
96 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
97 selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
98 checkedPropertiesCount: number = 0;
99 checkedChildPropertiesCount: number = 0;
101 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
102 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
103 displayClearSearch = false;
104 searchPropertyName:string;
106 isInputsTabSelected:boolean;
107 isPropertiesTabSelected:boolean;
108 isPoliciesTabSelected:boolean;
110 resourceIsReadonly:boolean;
111 loadingInstances:boolean = false;
112 loadingInputs:boolean = false;
113 loadingPolicies:boolean = false;
114 loadingProperties:boolean = false;
115 changedData:Array<PropertyFEModel|InputFEModel>;
116 hasChangedData:boolean;
117 isValidChangedData:boolean;
118 savingChangedData:boolean;
119 stateChangeStartUnregister:Function;
120 serviceBePropertiesMap: InstanceBePropertiesMap;
121 serviceBeCapabilitiesPropertiesMap: InstanceBePropertiesMap;
122 selectedInstance_FlattenCapabilitiesList: Array<Capability>;
124 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
125 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
126 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
128 constructor(private propertiesService: PropertiesService,
129 private hierarchyNavService: HierarchyNavService,
130 private propertiesUtils:PropertiesUtils,
131 private inputsUtils:InputsUtils,
132 private componentServiceNg2:ComponentServiceNg2,
133 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
134 @Inject("$stateParams") _stateParams,
135 @Inject("$scope") private $scope:ng.IScope,
136 @Inject("$state") private $state:ng.ui.IStateService,
137 @Inject("Notification") private Notification:any,
138 private componentModeService:ComponentModeService,
139 private ModalService:ModalService,
140 private EventListenerService:EventListenerService,
141 private ModalServiceSdcUI: SdcUiComponents.ModalService) {
143 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
145 /* 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
146 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
147 this.component = _stateParams.component;
148 this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
149 this.updateViewMode();
151 this.changedData = [];
152 this.updateHasChangedData();
153 this.isValidChangedData = true;
157 console.log("==>" + this.constructor.name + ": ngOnInit");
158 this.loadingInputs = true;
159 this.loadingPolicies = true;
160 this.loadingInstances = true;
161 this.loadingProperties = true;
162 this.componentServiceNg2
163 .getComponentInputsWithProperties(this.component)
164 .subscribe(response => {
165 _.forEach(response.inputs, (input: InputBEModel) => {
166 const newInput: InputFEModel = new InputFEModel(input);
167 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
168 this.inputs.push(newInput); //only push items that were declared via SDC
170 this.loadingInputs = false;
173 this.componentServiceNg2
174 .getComponentResourcePropertiesData(this.component)
175 .subscribe(response => {
176 this.loadingPolicies = false;
178 this.instances.push(...response.componentInstances);
179 this.instances.push(...response.groupInstances);
181 _.forEach(response.policies, (policy: any) => {
182 const newPolicy: InputFEModel = new InputFEModel(policy);
183 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
184 this.policies.push(policy);
187 // add the service self instance to the top of the list.
188 const serviceInstance = new ComponentInstance();
189 serviceInstance.name = SERVICE_SELF_TITLE;
190 serviceInstance.uniqueId = this.component.uniqueId;
191 this.instances.unshift(serviceInstance);
193 _.forEach(this.instances, (instance) => {
194 this.instancesNavigationData.push(instance);
195 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
197 this.loadingInstances = false;
198 if (this.instancesNavigationData[0] == undefined) {
199 this.loadingProperties = false;
201 this.selectFirstInstanceByDefault();
204 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
205 // stop if has changed properties
206 if (this.hasChangedData) {
207 event.preventDefault();
208 this.showUnsavedChangesAlert().then(() => {
209 this.$state.go(toState, toParams);
216 this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
217 this.stateChangeStartUnregister();
220 selectFirstInstanceByDefault = () => {
221 if (this.instancesNavigationData[0] !== undefined) {
222 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
226 updateViewMode = () => {
227 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
230 onCheckout = (component:ComponentData) => {
231 this.component = component;
232 this.updateViewMode();
235 isSelf = ():boolean => {
236 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
239 getServiceProperties(){
240 this.loadingProperties = false;
241 this.componentServiceNg2
242 .getServiceProperties(this.component)
243 .subscribe(response => {
244 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
245 this.serviceBePropertiesMap[this.component.uniqueId] = response;
246 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
247 this.loadingProperties = false;
249 this.loadingProperties = false;
253 onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
254 // stop if has changed properties
255 if (this.hasChangedData) {
256 this.showUnsavedChangesAlert().then((resolve)=> {
257 this.changeSelectedInstance(instance)
262 this.changeSelectedInstance(instance);
265 changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
266 this.selectedInstanceData = instance;
267 this.loadingProperties = true;
268 if (instance instanceof ComponentInstance) {
269 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
270 this.selectedInstance_FlattenCapabilitiesList = instance.capabilities ? CapabilitiesGroup.getFlattenedCapabilities(instance.capabilities) : [];
271 if (this.isInput(instance.originType)) {
272 this.componentInstanceServiceNg2
273 .getComponentInstanceInputs(this.component, instance)
274 .subscribe(response => {
275 instanceBePropertiesMap[instance.uniqueId] = response;
276 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
277 this.processInstanceCapabilitiesPropertiesResponse(false);
278 this.loadingProperties = false;
281 } else if (this.isSelf()) {
282 this.getServiceProperties();
284 this.componentInstanceServiceNg2
285 .getComponentInstanceProperties(this.component, instance.uniqueId)
286 .subscribe(response => {
287 instanceBePropertiesMap[instance.uniqueId] = response;
288 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
289 this.processInstanceCapabilitiesPropertiesResponse(false);
290 this.loadingProperties = false;
295 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
296 } else if (instance instanceof GroupInstance) {
297 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
298 this.componentInstanceServiceNg2
299 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
300 .subscribe((response) => {
301 instanceBePropertiesMap[instance.uniqueId] = response;
302 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
303 this.loadingProperties = false;
305 } else if (instance instanceof PolicyInstance) {
306 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
307 this.componentInstanceServiceNg2
308 .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
309 .subscribe((response) => {
310 instanceBePropertiesMap[instance.uniqueId] = response;
311 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
312 this.loadingProperties = false;
315 this.loadingProperties = false;
318 if (this.searchPropertyName) {
321 //clear selected property from the navigation
322 this.selectedFlatProperty = new SimpleFlatProperty();
323 this.propertiesNavigationData = [];
327 * Entry point handling response from server
329 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
330 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
331 this.checkedPropertiesCount = 0;
332 this.checkedChildPropertiesCount = 0;
335 processInstanceCapabilitiesPropertiesResponse = (originTypeIsVF: boolean) => {
336 let selectedComponentInstanceData = <ComponentInstance>(this.selectedInstanceData);
337 let currentUniqueId = this.selectedInstanceData.uniqueId;
338 this.serviceBeCapabilitiesPropertiesMap = new InstanceBePropertiesMap();
339 let isCapabilityOwnedByInstance: boolean;
340 this.serviceBeCapabilitiesPropertiesMap[currentUniqueId] = _.reduce(
341 this.selectedInstance_FlattenCapabilitiesList,
342 (result, cap: Capability) => {
343 isCapabilityOwnedByInstance = cap.ownerId === currentUniqueId ||
344 selectedComponentInstanceData.isServiceProxy() && cap.ownerId === selectedComponentInstanceData.sourceModelUid;
345 if (cap.properties && isCapabilityOwnedByInstance) {
346 _.forEach(cap.properties, prop => {
347 if (!prop.origName) {
348 prop.origName = prop.name;
349 prop.name = cap.name + '_' + prop.name;//for display. (before save - the name returns to its orig value: prop.name)
352 return result.concat(cap.properties);
356 let instanceFECapabilitiesPropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(this.serviceBeCapabilitiesPropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
357 //update FECapabilitiesProperties with their origName according to BeCapabilitiesProperties
358 _.forEach(instanceFECapabilitiesPropertiesMap[currentUniqueId], prop => {
359 prop.origName = _.find(this.serviceBeCapabilitiesPropertiesMap[currentUniqueId], p => p.uniqueId === prop.uniqueId).origName;
361 //concatenate capabilitiesProps to all props list
362 this.instanceFePropertiesMap[currentUniqueId] = (this.instanceFePropertiesMap[currentUniqueId] || []).concat(instanceFECapabilitiesPropertiesMap[currentUniqueId]);
363 this.checkedPropertiesCount = 0;
366 isCapabilityProperty = (prop: PropertyBEModel) => {
367 return _.find(this.selectedInstance_FlattenCapabilitiesList, cap => cap.uniqueId === prop.parentUniqueId);
370 /*** VALUE CHANGE EVENTS ***/
371 dataChanged = (item:PropertyFEModel|InputFEModel) => {
373 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
374 itemHasChanged = item.hasValueObjChanged();
375 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
376 itemHasChanged = item.hasDefaultValueChanged();
377 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
378 itemHasChanged = item.hasDefaultValueChanged();
381 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
382 if (itemHasChanged) {
383 if (dataChangedIdx === -1) {
384 this.changedData.push(item);
387 if (dataChangedIdx !== -1) {
388 this.changedData.splice(dataChangedIdx, 1);
392 if (this.isPropertiesTabSelected) {
393 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
394 } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
395 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
397 this.updateHasChangedData();
401 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
404 * Handle select node in navigation area, and select the row in table
406 onPropertySelectedUpdate = ($event) => {
407 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
408 this.selectedFlatProperty = $event;
409 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
410 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
414 * When user select row in table, this will prepare the hirarchy object for the tree.
416 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
417 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
418 let property = propertyRowSelectedEvent.propertyModel;
419 let instanceName = propertyRowSelectedEvent.instanceName;
420 this.propertyStructureHeader = null;
422 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
423 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
424 let simpleFlatProperty:Array<SimpleFlatProperty>;
425 if (property instanceof PropertyFEModel) {
426 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
427 } else if (property instanceof DerivedFEProperty) {
428 // Need to find parent PropertyFEModel
429 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
430 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
432 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
434 this.propertiesNavigationData = simpleFlatProperty;
437 // Update the header in the navigation tree with property name.
438 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
440 // Set selected property in table
441 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
442 this.hierarchyNavTabs.triggerTabChange('Property Structure');
446 selectInstanceRow = ($event) => {//get instance name
447 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
448 return instance.name == $event;
450 this.hierarchyNavTabs.triggerTabChange('Composition');
453 tabChanged = (event) => {
454 // stop if has changed properties
455 if (this.hasChangedData) {
456 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
457 this.showUnsavedChangesAlert().then((proceed) => {
458 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
464 console.log("==>" + this.constructor.name + ": tabChanged " + event);
465 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
466 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
467 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
468 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
469 this.propertyStructureHeader = null;
470 this.searchQuery = '';
475 /*** DECLARE PROPERTIES/INPUTS ***/
476 declareProperties = (): void => {
477 console.log("==>" + this.constructor.name + ": declareProperties");
479 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
480 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
481 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
482 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
483 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
485 angular.forEach(instancesIds, (instanceId: string): void => {
486 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
487 if (selectedInstanceData instanceof ComponentInstance) {
488 if (!this.isInput(selectedInstanceData.originType)) {
489 // convert Property FE model -> Property BE model, extract only checked
490 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
492 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
494 } else if (selectedInstanceData instanceof GroupInstance) {
495 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
496 } else if (selectedInstanceData instanceof PolicyInstance) {
497 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
501 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
503 //move changed capabilities properties from componentInstanceInputsMap obj to componentInstanceProperties
504 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] =
505 (inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId] || []).concat(
507 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
508 (prop: PropertyBEModel) => this.isCapabilityProperty(prop)
511 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId] = _.filter(
512 inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId],
513 prop => !this.isCapabilityProperty(prop)
515 if (inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId].length === 0) {
516 delete inputsToCreate.componentInstanceInputsMap[this.selectedInstanceData.uniqueId];
519 let isCapabilityPropertyChanged = false;
521 inputsToCreate.componentInstanceProperties[this.selectedInstanceData.uniqueId],
522 (prop: PropertyBEModel) => {
523 prop.name = prop.origName || prop.name;
524 if (this.isCapabilityProperty(prop)) {
525 isCapabilityPropertyChanged = true;
530 this.componentServiceNg2
531 .createInput(this.component, inputsToCreate, this.isSelf())
532 .subscribe(response => {
533 this.setInputTabIndication(response.length);
534 this.checkedPropertiesCount = 0;
535 this.checkedChildPropertiesCount = 0;
536 _.forEach(response, (input: InputBEModel) => {
537 let newInput: InputFEModel = new InputFEModel(input);
538 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
539 this.inputs.push(newInput);
540 this.updatePropertyValueAfterDeclare(newInput);
542 if (isCapabilityPropertyChanged) {
543 this.reloadInstanceCapabilities();
545 }, error => {}); //ignore error
548 declareListProperties = (): void => {
549 console.log('declareListProperties() - enter');
551 // get selected properties
552 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
553 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
554 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
555 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
556 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
557 let propertyNameList: Array<string> = [];
560 angular.forEach(instancesIds, (instanceId: string): void => {
561 console.log("instanceId="+instanceId);
563 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
564 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
566 if (selectedInstanceData instanceof ComponentInstance) {
567 if (!this.isInput(selectedInstanceData.originType)) {
568 // convert Property FE model -> Property BE model, extract only checked
569 selectedComponentInstancesProperties[instanceId] = checkedProperties;
571 selectedComponentInstancesInputs[instanceId] = checkedProperties;
573 } else if (selectedInstanceData instanceof GroupInstance) {
574 selectedGroupInstancesProperties[instanceId] = checkedProperties;
575 } else if (selectedInstanceData instanceof PolicyInstance) {
576 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
579 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
580 propertyNameList.push(property.name);
584 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
586 let modalTitle = 'Declare Properties as List Input';
587 const modal = this.ModalService.createCustomModal(new ModalModel(
589 modalTitle, /* title */
594 'blue', /* css class */
595 () => { /* callback */
596 let content:any = modal.instance.dynamicContent.instance;
599 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
600 let typelist: any = PROPERTY_TYPES.LIST;
601 let uniID: any = insId;
602 let boolfalse: any = false;
606 "type": content.propertyModel.simpleType,
607 "required": boolfalse
610 let schemaProp :any = {
611 "type": content.propertyModel.simpleType,
612 "required": boolfalse
615 reglistInput.description = content.propertyModel.description;
616 reglistInput.name = content.propertyModel.name;
617 reglistInput.type = typelist;
618 reglistInput.schemaType = content.propertyModel.simpleType;
619 reglistInput.instanceUniqueId = uniID;
620 reglistInput.uniqueId = uniID;
621 reglistInput.required =boolfalse;
622 reglistInput.schema = schem;
623 reglistInput.schemaProperty = schemaProp;
626 componentInstInputsMap: content.inputsToCreate,
627 listInput: reglistInput
629 console.log("save button clicked. input=", input);
631 this.componentServiceNg2
632 .createListInput(this.component, input, this.isSelf())
633 .subscribe(response => {
634 this.setInputTabIndication(response.length);
635 this.checkedPropertiesCount = 0;
636 this.checkedChildPropertiesCount = 0;
637 _.forEach(response, (input: InputBEModel) => {
638 let newInput: InputFEModel = new InputFEModel(input);
639 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
640 this.inputs.push(newInput);
641 // create list input does not return updated properties info, so need to reload
642 //this.updatePropertyValueAfterDeclare(newInput);
643 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
644 this.changeSelectedInstance(this.selectedInstanceData);
646 modal.instance.close();
648 }, error => {}); //ignore error
651 /*, getDisabled: function */
653 new ButtonModel('Cancel', 'outline grey', () => {
654 modal.instance.close();
659 // 3rd arg is passed to DeclareListComponent instance
660 this.ModalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
661 modal.instance.open();
662 console.log('declareListProperties() - leave');
665 /*** DECLARE PROPERTIES/POLICIES ***/
666 declarePropertiesToPolicies = (): void => {
667 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
668 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
670 angular.forEach(instancesIds, (instanceId: string): void => {
671 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
672 if (selectedInstanceData instanceof ComponentInstance) {
673 if (!this.isInput(selectedInstanceData.originType)) {
674 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
679 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
680 this.loadingPolicies = true;
682 this.componentServiceNg2
683 .createPolicy(this.component, policiesToCreate, this.isSelf())
684 .subscribe(response => {
685 this.setPolicyTabIndication(response.length);
686 this.checkedPropertiesCount = 0;
687 this.displayPoliciesAsDeclared(response);
688 this.loadingPolicies = false;
693 displayPoliciesAsDeclared = (policies) => {
694 _.forEach(policies, (policy: any) => {
695 let newPolicy: InputFEModel = new InputFEModel(policy);
696 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
697 newPolicy.relatedPropertyName = policy.name;
698 newPolicy.relatedPropertyValue = policy.value;
699 this.updatePropertyValueAfterDeclare(newPolicy);
700 this.policies.push(policy);
705 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
706 return new Promise((resolve, reject) => {
707 if (!this.isValidChangedData) {
708 reject('Changed data is invalid - cannot save!');
711 if (!this.changedData.length) {
716 // make request and its handlers
718 let handleSuccess, handleError;
719 let changedInputsProperties = [], changedCapabilitiesProperties = [];
720 if (this.isPropertiesTabSelected) {
721 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
722 changedProp = <PropertyFEModel>changedProp;
723 const propBE = new PropertyBEModel(changedProp);
724 propBE.toscaPresentation = new ToscaPresentationData();
725 propBE.toscaPresentation.ownerId = changedProp.parentUniqueId;
726 propBE.value = changedProp.getJSONValue();
727 propBE.name = changedProp.origName || changedProp.name;
728 delete propBE.origName;
731 changedCapabilitiesProperties = _.filter(changedProperties, prop => this.isCapabilityProperty(prop));
733 if (this.selectedInstanceData instanceof ComponentInstance) {
734 if (this.isInput(this.selectedInstanceData.originType)) {
735 changedInputsProperties = _.filter(changedProperties, prop => !this.isCapabilityProperty(prop));
736 if (changedInputsProperties.length && changedCapabilitiesProperties.length) {
737 request = Observable.forkJoin(
738 this.componentInstanceServiceNg2.updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties),
739 this.componentInstanceServiceNg2.updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties)
742 else if (changedInputsProperties.length) {
743 request = this.componentInstanceServiceNg2
744 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedInputsProperties);
746 else if (changedCapabilitiesProperties.length) {
747 request = this.componentInstanceServiceNg2
748 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedCapabilitiesProperties);
750 handleSuccess = (response) => {
751 // reset each changed property with new value and remove it from changed properties list
752 response.forEach((resInput) => {
753 const changedProp = <PropertyFEModel>this.changedData.shift();
754 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
756 console.log('updated instance inputs:', response);
760 request = this.componentServiceNg2.updateServiceProperties(this.component, _.map(changedProperties, cp => {
761 delete cp.constraints;
765 request = this.componentInstanceServiceNg2
766 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
768 handleSuccess = (response) => {
769 // reset each changed property with new value and remove it from changed properties list
770 response.forEach((resProp) => {
771 const changedProp = <PropertyFEModel>_.find(this.changedData, changedDataObject => changedDataObject.uniqueId === resProp.uniqueId);
772 this.changedData = _.filter(this.changedData, changedDataObject => changedDataObject.uniqueId !== resProp.uniqueId);
773 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
776 console.log("updated instance properties: ", response);
779 } else if (this.selectedInstanceData instanceof GroupInstance) {
780 request = this.componentInstanceServiceNg2
781 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
782 handleSuccess = (response) => {
783 // reset each changed property with new value and remove it from changed properties list
784 response.forEach((resProp) => {
785 const changedProp = <PropertyFEModel>this.changedData.shift();
786 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
789 console.log("updated group instance properties: ", response);
791 } else if (this.selectedInstanceData instanceof PolicyInstance) {
792 request = this.componentInstanceServiceNg2
793 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
794 handleSuccess = (response) => {
795 // reset each changed property with new value and remove it from changed properties list
796 response.forEach((resProp) => {
797 const changedProp = <PropertyFEModel>this.changedData.shift();
798 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
801 console.log("updated policy instance properties: ", response);
804 } else if (this.isInputsTabSelected) {
805 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
806 changedInput = <InputFEModel>changedInput;
807 const inputBE = new InputBEModel(changedInput);
808 inputBE.defaultValue = changedInput.getJSONDefaultValue();
811 request = this.componentServiceNg2
812 .updateComponentInputs(this.component, changedInputs);
813 handleSuccess = (response) => {
814 // reset each changed property with new value and remove it from changed properties list
815 response.forEach((resInput) => {
816 const changedInput = <InputFEModel>this.changedData.shift();
817 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
819 console.log("updated the component inputs and got this response: ", response);
823 this.savingChangedData = true;
826 this.savingChangedData = false;
827 if (changedCapabilitiesProperties.length) {
828 this.reloadInstanceCapabilities();
830 handleSuccess && handleSuccess(response);
831 this.updateHasChangedData();
835 this.savingChangedData = false;
836 handleError && handleError(error);
837 this.updateHasChangedData();
844 reloadInstanceCapabilities = (): void => {
845 let currentInstanceIndex = _.findIndex(this.instances, instance => instance.uniqueId == this.selectedInstanceData.uniqueId);
846 this.componentServiceNg2.getComponentResourceInstances(this.component).subscribe(result => {
847 let instanceCapabilitiesData: CapabilitiesGroup = _.reduce(result.componentInstances, (res, instance) => {
848 if (instance.uniqueId === this.selectedInstanceData.uniqueId) {
849 return instance.capabilities;
852 }, new CapabilitiesGroup());
853 (<ComponentInstance>this.instances[currentInstanceIndex]).capabilities = instanceCapabilitiesData;
857 reverseChangedData = ():void => {
858 // make reverse item handler
859 let handleReverseItem;
860 if (this.isPropertiesTabSelected) {
861 handleReverseItem = (changedItem) => {
862 changedItem = <PropertyFEModel>changedItem;
863 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
864 this.checkedPropertiesCount = 0;
865 this.checkedChildPropertiesCount = 0;
867 } else if (this.isInputsTabSelected) {
868 handleReverseItem = (changedItem) => {
869 changedItem = <InputFEModel>changedItem;
870 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
874 this.changedData.forEach(handleReverseItem);
875 this.changedData = [];
876 this.updateHasChangedData();
879 updateHasChangedData = ():boolean => {
880 const curHasChangedData:boolean = (this.changedData.length > 0);
881 if (curHasChangedData !== this.hasChangedData) {
882 this.hasChangedData = curHasChangedData;
883 if(this.hasChangedData) {
884 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
886 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
889 return this.hasChangedData;
892 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
893 this.saveChangedData().then(
895 this.Notification.success({
896 message: 'Successfully saved changes',
899 if(onSuccessFunction) onSuccessFunction();
900 if(this.isPropertiesTabSelected){
901 this.checkedPropertiesCount = 0;
902 this.checkedChildPropertiesCount = 0;
906 this.Notification.error({
907 message: 'Failed to save changes!',
910 if(onError) onError();
915 showUnsavedChangesAlert = ():Promise<any> => {
916 let modalTitle:string;
917 if (this.isPropertiesTabSelected) {
918 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
919 } else if (this.isInputsTabSelected) {
920 modalTitle = `Unsaved inputs for ${this.component.name}`;
923 return new Promise<any>((resolve, reject) => {
924 const modal = this.ModalServiceSdcUI.openCustomModal(
932 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
933 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
934 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
935 ] as IModalButtonComponent[]
936 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
941 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
942 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
943 let instanceName = input.instanceUniqueId.slice(input.instanceUniqueId.lastIndexOf('.') + 1);
944 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
945 return feProperty.uniqueId === input.propertyId &&
946 (feProperty.name == input.relatedPropertyName || input.name === instanceName.concat('_').concat(feProperty.name.replace(/[.]/g, '_')));
948 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
949 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
950 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
951 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
955 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
956 updateCheckedPropertyCount = (increment: boolean): void => {
957 this.checkedPropertiesCount += (increment) ? 1 : -1;
958 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
961 updateCheckedChildPropertyCount = (increment: boolean): void => {
962 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
965 setInputTabIndication = (numInputs: number): void => {
966 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
969 setPolicyTabIndication = (numPolicies: number): void => {
970 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
973 resetUnsavedChangesForInput = (input:InputFEModel) => {
974 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
975 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
976 this.updateHasChangedData();
979 deleteInput = (input: InputFEModel) => {
980 //reset any unsaved changes to the input before deleting it
981 this.resetUnsavedChangesForInput(input);
983 console.log("==>" + this.constructor.name + ": deleteInput");
984 let inputToDelete = new InputBEModel(input);
986 this.componentServiceNg2
987 .deleteInput(this.component, inputToDelete)
988 .subscribe(response => {
989 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
991 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
992 this.changeSelectedInstance(this.selectedInstanceData);
993 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
995 // if (instanceFeProperties) {
996 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
997 // return prop.name == input.propertyName;
1000 // if (propToEnable) {
1001 // if (propToEnable.name == response.inputPath) response.inputPath = null;
1002 // propToEnable.setNonDeclared(response.inputPath);
1003 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
1004 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
1007 }, error => {}); //ignore error
1010 deletePolicy = (policy: PolicyInstance) => {
1011 this.loadingPolicies = true;
1012 this.componentServiceNg2
1013 .deletePolicy(this.component, policy)
1014 .subscribe(response => {
1015 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
1016 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
1017 this.changeSelectedInstance(this.selectedInstanceData);
1018 this.loadingPolicies = false;
1022 deleteProperty = (property: PropertyFEModel) => {
1023 let propertyToDelete = new PropertyFEModel(property);
1024 this.loadingProperties = true;
1025 let feMap = this.instanceFePropertiesMap;
1026 this.componentServiceNg2
1027 .deleteServiceProperty(this.component, propertyToDelete)
1028 .subscribe(response => {
1029 const props = feMap[this.component.uniqueId];
1030 props.splice(props.findIndex(p => p.uniqueId === response),1);
1031 this.loadingProperties = false;
1033 this.loadingProperties = false;
1034 console.error(error);
1038 /*** addProperty ***/
1039 addProperty = () => {
1040 let modalTitle = 'Add Property';
1041 const modal = this.ModalService.createCustomModal(new ModalModel(
1046 new ButtonModel('Save', 'blue', () => {
1047 modal.instance.dynamicContent.instance.isLoading = true;
1048 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
1049 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
1050 .subscribe(response => {
1051 modal.instance.dynamicContent.instance.isLoading = false;
1052 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
1053 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
1054 modal.instance.close();
1056 modal.instance.dynamicContent.instance.isLoading = false;
1057 this.Notification.error({
1058 message: 'Failed to add property:' + error,
1063 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
1064 new ButtonModel('Cancel', 'outline grey', () => {
1065 modal.instance.close();
1070 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
1071 modal.instance.open();
1074 /*** SEARCH RELATED FUNCTIONS ***/
1075 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
1076 let instanceBePropertiesMap:InstanceBePropertiesMap;
1077 this.componentServiceNg2
1078 .filterComponentInstanceProperties(this.component, filterData)
1079 .subscribe(response => {
1081 this.processInstancePropertiesResponse(response, false);
1082 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
1083 this.searchPropertyName = filterData.propertyName;//mark in table
1084 this.hierarchyNavTabs.triggerTabChange('Composition');
1085 this.propertiesNavigationData = [];
1086 this.displayClearSearch = true;
1087 }, error => {}); //ignore error
1091 clearSearch = () => {
1092 this.instancesNavigationData = this.instances;
1093 this.searchPropertyName = "";
1094 this.hierarchyPropertiesDisplayOptions.searchText = "";
1095 this.displayClearSearch = false;
1096 this.advanceSearch.clearAll();
1097 this.searchQuery = '';
1100 clickOnClearSearch = () => {
1102 this.selectFirstInstanceByDefault();
1103 this.hierarchyNavTabs.triggerTabChange('Composition');
1106 private isInput = (instanceType:string):boolean =>{
1107 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;