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";
24 import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData, ModalModel, ButtonModel } from "app/models";
25 import { ResourceType } from "app/utils";
26 import {ComponentServiceNg2} from "../../services/component-services/component.service";
27 import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
28 import { InputBEModel, InputFEModel, ComponentInstance, GroupInstance, PolicyInstance, PropertyBEModel, DerivedFEProperty, SimpleFlatProperty } from "app/models";
29 import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
30 import {WorkspaceMode, EVENTS} from "../../../utils/constants";
31 import {EventListenerService} from "app/services/event-listener-service"
32 import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options";
33 import {FilterPropertiesAssignmentComponent} from "../../components/logic/filter-properties-assignment/filter-properties-assignment.component";
34 import {PropertyRowSelectedEvent} from "../../components/logic/properties-table/properties-table.component";
35 import {HierarchyNavService} from "./services/hierarchy-nav.service";
36 import {PropertiesUtils} from "./services/properties.utils";
37 import {ComponentModeService} from "../../services/component-services/component-mode.service";
38 import {ModalService} from "../../services/modal.service";
39 import {Tabs, Tab} from "../../components/ui/tabs/tabs.component";
40 import {InputsUtils} from "./services/inputs.utils";
41 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
42 import {DeclareListComponent} from "./declare-list/declare-list.component";
43 import { InstanceFeDetails } from "../../../models/instance-fe-details";
44 import { SdcUiComponents } from "sdc-ui/lib/angular";
45 //import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service";
46 import { IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config";
47 import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
48 import { DataTypeService } from "app/ng2/services/data-type.service";
49 import { DataTypeModel } from "app/models";
50 import { PROPERTY_DATA, PROPERTY_TYPES } from "app/utils";
51 import { PropertyDeclareAPIModel} from "app/models";
53 const SERVICE_SELF_TITLE = "SELF";
55 templateUrl: './properties-assignment.page.component.html',
56 styleUrls: ['./properties-assignment.page.component.less']
58 export class PropertiesAssignmentComponent {
59 title = "Properties & Inputs";
61 component: ComponentData;
62 componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
64 propertiesNavigationData = [];
65 instancesNavigationData = [];
67 instanceFePropertiesMap:InstanceFePropertiesMap;
68 inputs: Array<InputFEModel> = [];
69 policies: Array<PolicyInstance> = [];
70 instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
72 propertyStructureHeader: string;
74 selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
75 selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
76 checkedPropertiesCount: number = 0;
77 checkedChildPropertiesCount: number = 0;
79 hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
80 hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
81 displayClearSearch = false;
82 searchPropertyName:string;
84 isInputsTabSelected:boolean;
85 isPropertiesTabSelected:boolean;
86 isPoliciesTabSelected:boolean;
88 resourceIsReadonly:boolean;
89 loadingInstances:boolean = false;
90 loadingInputs:boolean = false;
91 loadingPolicies:boolean = false;
92 loadingProperties:boolean = false;
93 changedData:Array<PropertyFEModel|InputFEModel>;
94 hasChangedData:boolean;
95 isValidChangedData:boolean;
96 savingChangedData:boolean;
97 stateChangeStartUnregister:Function;
98 serviceBePropertiesMap: InstanceBePropertiesMap;
100 @ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
101 @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
102 @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
104 constructor(private propertiesService: PropertiesService,
105 private hierarchyNavService: HierarchyNavService,
106 private propertiesUtils:PropertiesUtils,
107 private inputsUtils:InputsUtils,
108 private componentServiceNg2:ComponentServiceNg2,
109 private componentInstanceServiceNg2:ComponentInstanceServiceNg2,
110 @Inject("$stateParams") _stateParams,
111 @Inject("$scope") private $scope:ng.IScope,
112 @Inject("$state") private $state:ng.ui.IStateService,
113 @Inject("Notification") private Notification:any,
114 private componentModeService:ComponentModeService,
115 private ModalService:ModalService,
116 private EventListenerService:EventListenerService,
117 private ModalServiceSdcUI: SdcUiComponents.ModalService) {
119 this.instanceFePropertiesMap = new InstanceFePropertiesMap();
121 /* 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
122 than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
123 this.component = _stateParams.component;
124 this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
125 this.updateViewMode();
127 this.changedData = [];
128 this.updateHasChangedData();
129 this.isValidChangedData = true;
133 console.log("==>" + this.constructor.name + ": ngOnInit");
134 this.loadingInputs = true;
135 this.loadingPolicies = true;
136 this.loadingInstances = true;
137 this.loadingProperties = true;
138 this.componentServiceNg2
139 .getComponentInputsWithProperties(this.component)
140 .subscribe(response => {
141 _.forEach(response.inputs, (input: InputBEModel) => {
142 const newInput: InputFEModel = new InputFEModel(input);
143 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
144 this.inputs.push(newInput); //only push items that were declared via SDC
146 this.loadingInputs = false;
149 this.componentServiceNg2
150 .getComponentResourcePropertiesData(this.component)
151 .subscribe(response => {
152 this.loadingPolicies = false;
154 this.instances.push(...response.componentInstances);
155 this.instances.push(...response.groupInstances);
157 _.forEach(response.policies, (policy: any) => {
158 const newPolicy: InputFEModel = new InputFEModel(policy);
159 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
160 this.policies.push(policy);
163 // add the service self instance to the top of the list.
164 const serviceInstance = new ComponentInstance();
165 serviceInstance.name = SERVICE_SELF_TITLE;
166 serviceInstance.uniqueId = this.component.uniqueId;
167 this.instances.unshift(serviceInstance);
169 _.forEach(this.instances, (instance) => {
170 this.instancesNavigationData.push(instance);
171 this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
173 this.loadingInstances = false;
174 if (this.instancesNavigationData[0] == undefined) {
175 this.loadingProperties = false;
177 this.selectFirstInstanceByDefault();
180 this.stateChangeStartUnregister = this.$scope.$on('$stateChangeStart', (event, toState, toParams) => {
181 // stop if has changed properties
182 if (this.hasChangedData) {
183 event.preventDefault();
184 this.showUnsavedChangesAlert().then(() => {
185 this.$state.go(toState, toParams);
192 this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
193 this.stateChangeStartUnregister();
196 selectFirstInstanceByDefault = () => {
197 if (this.instancesNavigationData[0] !== undefined) {
198 this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
202 updateViewMode = () => {
203 this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW;
206 onCheckout = (component:ComponentData) => {
207 this.component = component;
208 this.updateViewMode();
211 isSelf = ():boolean => {
212 return this.selectedInstanceData && this.selectedInstanceData.uniqueId == this.component.uniqueId;
215 getServiceProperties(){
216 this.loadingProperties = false;
217 this.componentServiceNg2
218 .getServiceProperties(this.component)
219 .subscribe(response => {
220 this.serviceBePropertiesMap = new InstanceBePropertiesMap();
221 this.serviceBePropertiesMap[this.component.uniqueId] = response;
222 this.processInstancePropertiesResponse(this.serviceBePropertiesMap, false);
223 this.loadingProperties = false;
225 this.loadingProperties = false;
229 onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
230 // stop if has changed properties
231 if (this.hasChangedData) {
232 this.showUnsavedChangesAlert().then((resolve)=> {
233 this.changeSelectedInstance(instance)
238 this.changeSelectedInstance(instance);
241 changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
242 this.selectedInstanceData = instance;
243 this.loadingProperties = true;
244 if (instance instanceof ComponentInstance) {
245 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
246 if (this.isInput(instance.originType)) {
247 this.componentInstanceServiceNg2
248 .getComponentInstanceInputs(this.component, instance)
249 .subscribe(response => {
250 instanceBePropertiesMap[instance.uniqueId] = response;
251 this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
252 this.loadingProperties = false;
255 } else if (this.isSelf()) {
256 this.getServiceProperties();
258 this.componentInstanceServiceNg2
259 .getComponentInstanceProperties(this.component, instance.uniqueId)
260 .subscribe(response => {
261 instanceBePropertiesMap[instance.uniqueId] = response;
262 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
263 this.loadingProperties = false;
268 this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
269 } else if (instance instanceof GroupInstance) {
270 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
271 this.componentInstanceServiceNg2
272 .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
273 .subscribe((response) => {
274 instanceBePropertiesMap[instance.uniqueId] = response;
275 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
276 this.loadingProperties = false;
278 } else if (instance instanceof PolicyInstance) {
279 let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
280 this.componentInstanceServiceNg2
281 .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
282 .subscribe((response) => {
283 instanceBePropertiesMap[instance.uniqueId] = response;
284 this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
285 this.loadingProperties = false;
288 this.loadingProperties = false;
291 if (this.searchPropertyName) {
294 //clear selected property from the navigation
295 this.selectedFlatProperty = new SimpleFlatProperty();
296 this.propertiesNavigationData = [];
300 * Entry point handling response from server
302 processInstancePropertiesResponse = (instanceBePropertiesMap: InstanceBePropertiesMap, originTypeIsVF: boolean) => {
303 this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, originTypeIsVF, this.inputs); //create flattened children, disable declared props, and init values
304 this.checkedPropertiesCount = 0;
305 this.checkedChildPropertiesCount = 0;
309 /*** VALUE CHANGE EVENTS ***/
310 dataChanged = (item:PropertyFEModel|InputFEModel) => {
312 if (this.isPropertiesTabSelected && item instanceof PropertyFEModel) {
313 itemHasChanged = item.hasValueObjChanged();
314 } else if (this.isInputsTabSelected && item instanceof InputFEModel) {
315 itemHasChanged = item.hasDefaultValueChanged();
316 } else if (this.isPoliciesTabSelected && item instanceof InputFEModel) {
317 itemHasChanged = item.hasDefaultValueChanged();
320 const dataChangedIdx = this.changedData.findIndex((changedItem) => changedItem === item);
321 if (itemHasChanged) {
322 if (dataChangedIdx === -1) {
323 this.changedData.push(item);
326 if (dataChangedIdx !== -1) {
327 this.changedData.splice(dataChangedIdx, 1);
331 if (this.isPropertiesTabSelected) {
332 this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
333 } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
334 this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
336 this.updateHasChangedData();
340 /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/
343 * Handle select node in navigation area, and select the row in table
345 onPropertySelectedUpdate = ($event) => {
346 console.log("==>" + this.constructor.name + ": onPropertySelectedUpdate");
347 this.selectedFlatProperty = $event;
348 let parentProperty:PropertyFEModel = this.propertiesService.getParentPropertyFEModelFromPath(this.instanceFePropertiesMap[this.selectedFlatProperty.instanceName], this.selectedFlatProperty.path);
349 parentProperty.expandedChildPropertyId = this.selectedFlatProperty.path;
353 * When user select row in table, this will prepare the hirarchy object for the tree.
355 selectPropertyRow = (propertyRowSelectedEvent:PropertyRowSelectedEvent) => {
356 console.log("==>" + this.constructor.name + ": selectPropertyRow " + propertyRowSelectedEvent.propertyModel.name);
357 let property = propertyRowSelectedEvent.propertyModel;
358 let instanceName = propertyRowSelectedEvent.instanceName;
359 this.propertyStructureHeader = null;
361 // Build hirarchy tree for the navigation and update propertiesNavigationData with it.
362 if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
363 let simpleFlatProperty:Array<SimpleFlatProperty>;
364 if (property instanceof PropertyFEModel) {
365 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
366 } else if (property instanceof DerivedFEProperty) {
367 // Need to find parent PropertyFEModel
368 let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => {
369 return property.propertiesName.indexOf(tmpFeProperty.name)===0;
371 simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName);
373 this.propertiesNavigationData = simpleFlatProperty;
376 // Update the header in the navigation tree with property name.
377 this.propertyStructureHeader = (property.propertiesName.split('#'))[0];
379 // Set selected property in table
380 this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName);
381 this.hierarchyNavTabs.triggerTabChange('Property Structure');
385 selectInstanceRow = ($event) => {//get instance name
386 this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => {
387 return instance.name == $event;
389 this.hierarchyNavTabs.triggerTabChange('Composition');
392 tabChanged = (event) => {
393 // stop if has changed properties
394 if (this.hasChangedData) {
395 this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
396 this.showUnsavedChangesAlert().then((proceed) => {
397 this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
403 console.log("==>" + this.constructor.name + ": tabChanged " + event);
404 this.currentMainTab = this.propertyInputTabs.tabs.find((tab) => tab.title === event.title);
405 this.isPropertiesTabSelected = this.currentMainTab.title === "Properties";
406 this.isInputsTabSelected = this.currentMainTab.title === "Inputs";
407 this.isPoliciesTabSelected = this.currentMainTab.title === "Policies";
408 this.propertyStructureHeader = null;
409 this.searchQuery = '';
414 /*** DECLARE PROPERTIES/INPUTS ***/
415 declareProperties = (): void => {
416 console.log("==>" + this.constructor.name + ": declareProperties");
418 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
419 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
420 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
421 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
422 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
424 angular.forEach(instancesIds, (instanceId: string): void => {
425 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
426 if (selectedInstanceData instanceof ComponentInstance) {
427 if (!this.isInput(selectedInstanceData.originType)) {
428 // convert Property FE model -> Property BE model, extract only checked
429 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
431 selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
433 } else if (selectedInstanceData instanceof GroupInstance) {
434 selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
435 } else if (selectedInstanceData instanceof PolicyInstance) {
436 selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
440 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
442 this.componentServiceNg2
443 .createInput(this.component, inputsToCreate, this.isSelf())
444 .subscribe(response => {
445 this.setInputTabIndication(response.length);
446 this.checkedPropertiesCount = 0;
447 this.checkedChildPropertiesCount = 0;
448 _.forEach(response, (input: InputBEModel) => {
449 let newInput: InputFEModel = new InputFEModel(input);
450 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
451 this.inputs.push(newInput);
452 this.updatePropertyValueAfterDeclare(newInput);
454 }, error => {}); //ignore error
457 declareListProperties = (): void => {
458 console.log('declareListProperties() - enter');
460 // get selected properties
461 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
462 let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
463 let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
464 let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
465 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
466 let propertyNameList: Array<string> = [];
469 angular.forEach(instancesIds, (instanceId: string): void => {
470 console.log("instanceId="+instanceId);
472 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
473 let checkedProperties: PropertyBEModel[] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
475 if (selectedInstanceData instanceof ComponentInstance) {
476 if (!this.isInput(selectedInstanceData.originType)) {
477 // convert Property FE model -> Property BE model, extract only checked
478 selectedComponentInstancesProperties[instanceId] = checkedProperties;
480 selectedComponentInstancesInputs[instanceId] = checkedProperties;
482 } else if (selectedInstanceData instanceof GroupInstance) {
483 selectedGroupInstancesProperties[instanceId] = checkedProperties;
484 } else if (selectedInstanceData instanceof PolicyInstance) {
485 selectedPolicyInstancesProperties[instanceId] = checkedProperties;
488 angular.forEach(checkedProperties, (property: PropertyBEModel) => {
489 propertyNameList.push(property.name);
493 let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
495 let modalTitle = 'Declare Properties as List Input';
496 const modal = this.ModalService.createCustomModal(new ModalModel(
498 modalTitle, /* title */
503 'blue', /* css class */
504 () => { /* callback */
505 let content:any = modal.instance.dynamicContent.instance;
508 let reglistInput: InstanceBePropertiesMap = new InstanceBePropertiesMap();
509 let typelist: any = PROPERTY_TYPES.LIST;
510 let uniID: any = insId;
511 let boolfalse: any = false;
515 "type": content.propertyModel.simpleType,
516 "required": boolfalse
519 let schemaProp :any = {
520 "type": content.propertyModel.simpleType,
521 "required": boolfalse
524 reglistInput.description = content.propertyModel.description;
525 reglistInput.name = content.propertyModel.name;
526 reglistInput.type = typelist;
527 reglistInput.schemaType = content.propertyModel.simpleType;
528 reglistInput.instanceUniqueId = uniID;
529 reglistInput.uniqueId = uniID;
530 reglistInput.required =boolfalse;
531 reglistInput.schema = schem;
532 reglistInput.schemaProperty = schemaProp;
535 componentInstInputsMap: content.inputsToCreate,
536 listInput: reglistInput
538 console.log("save button clicked. input=", input);
540 this.componentServiceNg2
541 .createListInput(this.component, input, this.isSelf())
542 .subscribe(response => {
543 this.setInputTabIndication(response.length);
544 this.checkedPropertiesCount = 0;
545 this.checkedChildPropertiesCount = 0;
546 _.forEach(response, (input: InputBEModel) => {
547 let newInput: InputFEModel = new InputFEModel(input);
548 this.inputsUtils.resetInputDefaultValue(newInput, input.defaultValue);
549 this.inputs.push(newInput);
550 // create list input does not return updated properties info, so need to reload
551 //this.updatePropertyValueAfterDeclare(newInput);
552 // Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
553 this.changeSelectedInstance(this.selectedInstanceData);
555 modal.instance.close();
557 }, error => {}); //ignore error
560 /*, getDisabled: function */
562 new ButtonModel('Cancel', 'outline grey', () => {
563 modal.instance.close();
568 // 3rd arg is passed to DeclareListComponent instance
569 this.ModalService.addDynamicContentToModal(modal, DeclareListComponent, {properties: inputsToCreate, propertyNameList: propertyNameList});
570 modal.instance.open();
571 console.log('declareListProperties() - leave');
574 /*** DECLARE PROPERTIES/POLICIES ***/
575 declarePropertiesToPolicies = (): void => {
576 let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
577 let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
579 angular.forEach(instancesIds, (instanceId: string): void => {
580 let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
581 if (selectedInstanceData instanceof ComponentInstance) {
582 if (!this.isInput(selectedInstanceData.originType)) {
583 selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
588 let policiesToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(null, selectedComponentInstancesProperties, null, null);
589 this.loadingPolicies = true;
591 this.componentServiceNg2
592 .createPolicy(this.component, policiesToCreate, this.isSelf())
593 .subscribe(response => {
594 this.setPolicyTabIndication(response.length);
595 this.checkedPropertiesCount = 0;
596 this.displayPoliciesAsDeclared(response);
597 this.loadingPolicies = false;
602 displayPoliciesAsDeclared = (policies) => {
603 _.forEach(policies, (policy: any) => {
604 let newPolicy: InputFEModel = new InputFEModel(policy);
605 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
606 newPolicy.relatedPropertyName = policy.name;
607 newPolicy.relatedPropertyValue = policy.value;
608 this.updatePropertyValueAfterDeclare(newPolicy);
609 this.policies.push(policy);
614 saveChangedData = ():Promise<(PropertyBEModel|InputBEModel)[]> => {
615 return new Promise((resolve, reject) => {
616 if (!this.isValidChangedData) {
617 reject('Changed data is invalid - cannot save!');
620 if (!this.changedData.length) {
625 // make request and its handlers
627 let handleSuccess, handleError;
628 if (this.isPropertiesTabSelected) {
629 const changedProperties: PropertyBEModel[] = this.changedData.map((changedProp) => {
630 changedProp = <PropertyFEModel>changedProp;
631 const propBE = new PropertyBEModel(changedProp);
632 propBE.value = changedProp.getJSONValue();
636 if (this.selectedInstanceData instanceof ComponentInstance) {
637 if (this.isInput(this.selectedInstanceData.originType)) {
638 request = this.componentInstanceServiceNg2
639 .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties);
640 handleSuccess = (response) => {
641 // reset each changed property with new value and remove it from changed properties list
642 response.forEach((resInput) => {
643 const changedProp = <PropertyFEModel>this.changedData.shift();
644 this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
646 console.log('updated instance inputs:', response);
650 request = this.componentServiceNg2.updateServiceProperties(this.component, _.map(changedProperties, cp => {
651 delete cp.constraints;
655 request = this.componentInstanceServiceNg2
656 .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
658 handleSuccess = (response) => {
659 // reset each changed property with new value and remove it from changed properties list
660 response.forEach((resProp) => {
661 const changedProp = <PropertyFEModel>_.find(this.changedData, changedDataObject => changedDataObject.uniqueId === resProp.uniqueId);
662 this.changedData = _.filter(this.changedData, changedDataObject => changedDataObject.uniqueId !== resProp.uniqueId);
663 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
666 console.log("updated instance properties: ", response);
669 } else if (this.selectedInstanceData instanceof GroupInstance) {
670 request = this.componentInstanceServiceNg2
671 .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
672 handleSuccess = (response) => {
673 // reset each changed property with new value and remove it from changed properties list
674 response.forEach((resProp) => {
675 const changedProp = <PropertyFEModel>this.changedData.shift();
676 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
679 console.log("updated group instance properties: ", response);
681 } else if (this.selectedInstanceData instanceof PolicyInstance) {
682 request = this.componentInstanceServiceNg2
683 .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
684 handleSuccess = (response) => {
685 // reset each changed property with new value and remove it from changed properties list
686 response.forEach((resProp) => {
687 const changedProp = <PropertyFEModel>this.changedData.shift();
688 this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
691 console.log("updated policy instance properties: ", response);
694 } else if (this.isInputsTabSelected) {
695 const changedInputs: InputBEModel[] = this.changedData.map((changedInput) => {
696 changedInput = <InputFEModel>changedInput;
697 const inputBE = new InputBEModel(changedInput);
698 inputBE.defaultValue = changedInput.getJSONDefaultValue();
701 request = this.componentServiceNg2
702 .updateComponentInputs(this.component, changedInputs);
703 handleSuccess = (response) => {
704 // reset each changed property with new value and remove it from changed properties list
705 response.forEach((resInput) => {
706 const changedInput = <InputFEModel>this.changedData.shift();
707 this.inputsUtils.resetInputDefaultValue(changedInput, resInput.defaultValue);
709 console.log("updated the component inputs and got this response: ", response);
713 this.savingChangedData = true;
716 this.savingChangedData = false;
717 handleSuccess && handleSuccess(response);
718 this.updateHasChangedData();
722 this.savingChangedData = false;
723 handleError && handleError(error);
724 this.updateHasChangedData();
731 reverseChangedData = ():void => {
732 // make reverse item handler
733 let handleReverseItem;
734 if (this.isPropertiesTabSelected) {
735 handleReverseItem = (changedItem) => {
736 changedItem = <PropertyFEModel>changedItem;
737 this.propertiesUtils.resetPropertyValue(changedItem, changedItem.value);
738 this.checkedPropertiesCount = 0;
739 this.checkedChildPropertiesCount = 0;
741 } else if (this.isInputsTabSelected) {
742 handleReverseItem = (changedItem) => {
743 changedItem = <InputFEModel>changedItem;
744 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
748 this.changedData.forEach(handleReverseItem);
749 this.changedData = [];
750 this.updateHasChangedData();
753 updateHasChangedData = ():boolean => {
754 const curHasChangedData:boolean = (this.changedData.length > 0);
755 if (curHasChangedData !== this.hasChangedData) {
756 this.hasChangedData = curHasChangedData;
757 if(this.hasChangedData) {
758 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
760 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
763 return this.hasChangedData;
766 doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
767 this.saveChangedData().then(
769 this.Notification.success({
770 message: 'Successfully saved changes',
773 if(onSuccessFunction) onSuccessFunction();
774 if(this.isPropertiesTabSelected){
775 this.checkedPropertiesCount = 0;
776 this.checkedChildPropertiesCount = 0;
780 this.Notification.error({
781 message: 'Failed to save changes!',
784 if(onError) onError();
789 showUnsavedChangesAlert = ():Promise<any> => {
790 let modalTitle:string;
791 if (this.isPropertiesTabSelected) {
792 modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
793 } else if (this.isInputsTabSelected) {
794 modalTitle = `Unsaved inputs for ${this.component.name}`;
797 return new Promise<any>((resolve, reject) => {
798 const modal = this.ModalServiceSdcUI.openCustomModal(
806 {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
807 {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
808 {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
809 ] as IModalButtonComponent[]
810 }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
815 updatePropertyValueAfterDeclare = (input: InputFEModel) => {
816 if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
817 let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[input.instanceUniqueId], (feProperty: PropertyFEModel) => {
818 return feProperty.name == input.relatedPropertyName;
820 let inputPath = (input.inputPath && input.inputPath != propertyForUpdatindVal.name) ? input.inputPath : undefined;
821 propertyForUpdatindVal.setAsDeclared(inputPath); //set prop as declared before assigning value
822 this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, inputPath);
823 this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, input.relatedPropertyValue, inputPath);
827 //used for declare button, to keep count of newly checked properties (and ignore declared properties)
828 updateCheckedPropertyCount = (increment: boolean): void => {
829 this.checkedPropertiesCount += (increment) ? 1 : -1;
830 console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount);
833 updateCheckedChildPropertyCount = (increment: boolean): void => {
834 this.checkedChildPropertiesCount += (increment) ? 1 : -1;
837 setInputTabIndication = (numInputs: number): void => {
838 this.propertyInputTabs.setTabIndication('Inputs', numInputs);
841 setPolicyTabIndication = (numPolicies: number): void => {
842 this.propertyInputTabs.setTabIndication('Policies', numPolicies);
845 resetUnsavedChangesForInput = (input:InputFEModel) => {
846 this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
847 this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
848 this.updateHasChangedData();
851 deleteInput = (input: InputFEModel) => {
852 //reset any unsaved changes to the input before deleting it
853 this.resetUnsavedChangesForInput(input);
855 console.log("==>" + this.constructor.name + ": deleteInput");
856 let inputToDelete = new InputBEModel(input);
858 this.componentServiceNg2
859 .deleteInput(this.component, inputToDelete)
860 .subscribe(response => {
861 this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
863 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
864 this.changeSelectedInstance(this.selectedInstanceData);
865 // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
867 // if (instanceFeProperties) {
868 // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => {
869 // return prop.name == input.propertyName;
872 // if (propToEnable) {
873 // if (propToEnable.name == response.inputPath) response.inputPath = null;
874 // propToEnable.setNonDeclared(response.inputPath);
875 // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath);
876 // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath);
879 }, error => {}); //ignore error
882 deletePolicy = (policy: PolicyInstance) => {
883 this.loadingPolicies = true;
884 this.componentServiceNg2
885 .deletePolicy(this.component, policy)
886 .subscribe(response => {
887 this.policies = this.policies.filter(policy => policy.uniqueId !== response.uniqueId);
888 //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
889 this.changeSelectedInstance(this.selectedInstanceData);
890 this.loadingPolicies = false;
894 deleteProperty = (property: PropertyFEModel) => {
895 let propertyToDelete = new PropertyFEModel(property);
896 this.loadingProperties = true;
897 let feMap = this.instanceFePropertiesMap;
898 this.componentServiceNg2
899 .deleteServiceProperty(this.component, propertyToDelete)
900 .subscribe(response => {
901 const props = feMap[this.component.uniqueId];
902 props.splice(props.findIndex(p => p.uniqueId === response),1);
903 this.loadingProperties = false;
905 this.loadingProperties = false;
906 console.error(error);
910 /*** addProperty ***/
911 addProperty = () => {
912 let modalTitle = 'Add Property';
913 const modal = this.ModalService.createCustomModal(new ModalModel(
918 new ButtonModel('Save', 'blue', () => {
919 modal.instance.dynamicContent.instance.isLoading = true;
920 const newProperty: PropertyBEModel = modal.instance.dynamicContent.instance.propertyModel;
921 this.componentServiceNg2.createServiceProperty(this.component, newProperty)
922 .subscribe(response => {
923 modal.instance.dynamicContent.instance.isLoading = false;
924 let newProp: PropertyFEModel = this.propertiesUtils.convertAddPropertyBAToPropertyFE(response);
925 this.instanceFePropertiesMap[this.component.uniqueId].push(newProp);
926 modal.instance.close();
928 modal.instance.dynamicContent.instance.isLoading = false;
929 this.Notification.error({
930 message: 'Failed to add property:' + error,
935 }, () => !modal.instance.dynamicContent.instance.checkFormValidForSubmit()),
936 new ButtonModel('Cancel', 'outline grey', () => {
937 modal.instance.close();
942 this.ModalService.addDynamicContentToModal(modal, PropertyCreatorComponent, {});
943 modal.instance.open();
946 /*** SEARCH RELATED FUNCTIONS ***/
947 searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => {
948 let instanceBePropertiesMap:InstanceBePropertiesMap;
949 this.componentServiceNg2
950 .filterComponentInstanceProperties(this.component, filterData)
951 .subscribe(response => {
953 this.processInstancePropertiesResponse(response, false);
954 this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree
955 this.searchPropertyName = filterData.propertyName;//mark in table
956 this.hierarchyNavTabs.triggerTabChange('Composition');
957 this.propertiesNavigationData = [];
958 this.displayClearSearch = true;
959 }, error => {}); //ignore error
963 clearSearch = () => {
964 this.instancesNavigationData = this.instances;
965 this.searchPropertyName = "";
966 this.hierarchyPropertiesDisplayOptions.searchText = "";
967 this.displayClearSearch = false;
968 this.advanceSearch.clearAll();
969 this.searchQuery = '';
972 clickOnClearSearch = () => {
974 this.selectFirstInstanceByDefault();
975 this.hierarchyNavTabs.triggerTabChange('Composition');
978 private isInput = (instanceType:string):boolean =>{
979 return instanceType === ResourceType.VF || instanceType === ResourceType.PNF || instanceType === ResourceType.CVFC || instanceType === ResourceType.CR;