re base code
[sdc.git] / catalog-ui / src / app / view-models / workspace / tabs / composition / composition-view-model.ts
index 46c2d2e..a77377b 100644 (file)
  */
 'use strict';
 import * as _ from "lodash";
-import {Component, ComponentInstance, IAppMenu} from "app/models";
-import {SharingService, CacheService, EventListenerService, LeftPaletteLoaderService} from "app/services";
-import {ModalsHandler, GRAPH_EVENTS, ComponentFactory, ChangeLifecycleStateHandler, MenuHandler, EVENTS} from "app/utils";
-import {IWorkspaceViewModelScope} from "../../workspace-view-model";
-import {ComponentGenericResponse} from "app/ng2/services/responses/component-generic-response";
-import {Resource} from "app/models/components/resource";
-import {ResourceType,ComponentType} from "app/utils/constants";
-import {ComponentServiceFactoryNg2} from "app/ng2/services/component-services/component.service.factory";
-import {ServiceGenericResponse} from "app/ng2/services/responses/service-generic-response";
-import {Service} from "app/models/components/service";
+import { Component, ComponentInstance, IAppMenu, Requirement, Capability, ButtonModel } from "app/models";
+import { SharingService, CacheService, EventListenerService, LeftPaletteLoaderService } from "app/services";
+import { ModalsHandler, GRAPH_EVENTS, ComponentFactory, ChangeLifecycleStateHandler, MenuHandler, EVENTS, ComponentInstanceFactory } from "app/utils";
+import { IWorkspaceViewModelScope } from "../../workspace-view-model";
+import { ComponentGenericResponse } from "app/ng2/services/responses/component-generic-response";
+import { Resource } from "app/models/components/resource";
+import { ResourceType, ComponentType } from "app/utils/constants";
+import { ComponentServiceFactoryNg2 } from "app/ng2/services/component-services/component.service.factory";
+import { ServiceGenericResponse } from "app/ng2/services/responses/service-generic-response";
+import { Service } from "app/models/components/service";
+import { ZoneInstance } from "app/models/graph/zones/zone-instance";
+import { ComponentServiceNg2 } from "app/ng2/services/component-services/component.service";
+import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service"
+import { IModalConfig, IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config";
+import { ValueEditComponent } from "app/ng2/components/ui/forms/value-edit/value-edit.component";
+import { UnsavedChangesComponent } from "../../../../ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
+import { ModalButtonComponent } from "sdc-ui/lib/angular/components";
+
 
 
 export interface ICompositionViewModelScope extends IWorkspaceViewModelScope {
 
     currentComponent:Component;
+
+    //Added for now, in the future need to remove and use only id and type to pass to tabs.
     selectedComponent: Component;
+    selectedZoneInstance: ZoneInstance;
+
     componentInstanceNames: Array<string>;
     isLoading:boolean;
     graphApi:any;
@@ -42,21 +54,24 @@ export interface ICompositionViewModelScope extends IWorkspaceViewModelScope {
     sdcMenu:IAppMenu;
     version:string;
     isViewOnly:boolean;
+    isCanvasTagging:boolean;
     isLoadingRightPanel:boolean;
     disabledTabs:boolean;
     openVersionChangeModal(pathsToDelete:string[]):ng.IPromise<any>;
     onComponentInstanceVersionChange(component:Component);
     isComponentInstanceSelected():boolean;
-    updateSelectedComponent():void
+    updateSelectedComponent():void;
     openUpdateModal();
     deleteSelectedComponentInstance():void;
     onBackgroundClick():void;
     setSelectedInstance(componentInstance:ComponentInstance):void;
+    setSelectedZoneInstance(zoneInstance: ZoneInstance):void;
+    changeZoneInstanceName(newName:string):void;
     printScreen():void;
     isPNF():boolean;
     isConfiguration():boolean;
     preventMoveTab(state: boolean):void;
-
+    ComponentServiceNg2:ComponentServiceNg2,
     cacheComponentsInstancesFullData:Component;
 }
 
@@ -76,8 +91,11 @@ export class CompositionViewModel {
         'ChangeLifecycleStateHandler',
         'LeftPaletteLoaderService',
         'ModalsHandler',
+        'ModalServiceSdcUI',
         'EventListenerService',
-        'ComponentServiceFactoryNg2'
+        'ComponentServiceFactoryNg2',
+        'ComponentServiceNg2',
+        'Notification'
     ];
 
     constructor(private $scope:ICompositionViewModelScope,
@@ -93,8 +111,12 @@ export class CompositionViewModel {
                 private ChangeLifecycleStateHandler:ChangeLifecycleStateHandler,
                 private LeftPaletteLoaderService:LeftPaletteLoaderService,
                 private ModalsHandler:ModalsHandler,
+                private ModalServiceSdcUI: ModalServiceSdcUI,
                 private eventListenerService:EventListenerService,
-                private ComponentServiceFactoryNg2: ComponentServiceFactoryNg2) {
+                private ComponentServiceFactoryNg2: ComponentServiceFactoryNg2,
+                private ComponentServiceNg2:ComponentServiceNg2,
+                private Notification:any
+            ) {
 
         this.$scope.setValidState(true);
         this.initScope();
@@ -104,16 +126,17 @@ export class CompositionViewModel {
 
 
     private initGraphData = ():void => {
-        if(!this.$scope.component.componentInstances || !this.$scope.component.componentInstancesRelations ) {
+        if(!this.hasCompositionGraphData(this.$scope.component)) {
             this.$scope.isLoading = true;
             let service = this.ComponentServiceFactoryNg2.getComponentService(this.$scope.component);
             service.getComponentCompositionData(this.$scope.component).subscribe((response:ComponentGenericResponse) => {
                 if (this.$scope.component.isService()) {
                     (<Service> this.$scope.component).forwardingPaths = (<ServiceGenericResponse>response).forwardingPaths;
                 }
-                this.$scope.component.componentInstances = response.componentInstances;
-                this.$scope.component.componentInstancesRelations = response.componentInstancesRelations;
-                this.$scope.component.policies = response.policies;
+                this.$scope.component.componentInstances = response.componentInstances || [];
+                this.$scope.component.componentInstancesRelations = response.componentInstancesRelations || [];
+                this.$scope.component.policies = response.policies || [];
+                this.$scope.component.groupInstances = response.groupInstances || [];
                 this.$scope.isLoading = false;
                 this.initComponent();
                 this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED);
@@ -124,25 +147,134 @@ export class CompositionViewModel {
         this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_COMPOSITION_GRAPH_DATA_LOADED);
     };
 
+    private hasCompositionGraphData = (component:Component):boolean => {
+        return !!(component.componentInstances && component.componentInstancesRelations && component.policies && component.groupInstances);
+    };
 
     private cacheComponentsInstancesFullData:Array<Component>;
 
     private initComponent = ():void => {
         this.$scope.currentComponent = this.$scope.component;
         this.$scope.selectedComponent = this.$scope.currentComponent;
+        this.$scope.selectedZoneInstance = null;
         this.updateUuidMap();
         this.$scope.isViewOnly = this.$scope.isViewMode();
     };
 
     private registerGraphEvents = (scope:ICompositionViewModelScope):void => {
         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_NODE_SELECTED, scope.setSelectedInstance);
+        this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, scope.setSelectedZoneInstance);
         this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, scope.onBackgroundClick);
+        this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_CANVAS_TAG_START, () => { 
+            scope.isCanvasTagging = true;
+            this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, true, this.showUnsavedChangesAlert);
+        });
+        this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_CANVAS_TAG_END, () => { 
+            scope.isCanvasTagging = false; 
+            this.resetUnsavedChanges();
+        });
+        this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, scope.changeZoneInstanceName);
+        this.eventListenerService.registerObserverCallback(EVENTS.UPDATE_PANEL, this.removeSelectedZoneInstance);
     };
 
-    private openUpdateComponentInstanceNameModal = ():void => {
-        this.ModalsHandler.openUpdateComponentInstanceNameModal(this.$scope.currentComponent).then(()=> {
-            this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance);
+    private showUnsavedChangesAlert = (afterSave?:Function):Promise<any> => {
+        let deferred = new Promise<any>((resolve, reject)=> {
+            const modal = this.ModalServiceSdcUI.openCustomModal(
+                {
+                    title: "Unsaved Changes",
+                    size: 'sm',
+                    type: 'custom',
+                    
+                    buttons: [
+                        {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
+                        {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.resetUnsavedChanges(); resolve()}},
+                        {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, callback: () => {  reject(); this.saveUnsavedChanges(afterSave);  }}
+                ] as IModalButtonComponent[]
+            }, UnsavedChangesComponent, { isValidChangedData: true});
         });
+
+        return deferred;
+    }
+
+    private unRegisterGraphEvents = (scope: ICompositionViewModelScope):void => {
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_NODE_SELECTED, scope.setSelectedInstance);
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, scope.setSelectedZoneInstance);
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, scope.onBackgroundClick);
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_CANVAS_TAG_START);
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_CANVAS_TAG_END);
+        this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, scope.changeZoneInstanceName);
+        this.eventListenerService.unRegisterObserver(EVENTS.UPDATE_PANEL, this.removeSelectedZoneInstance);
+
+    };
+
+    private resetUnsavedChanges = () => {
+        this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
+    }
+
+    private saveUnsavedChanges = (afterSaveFunction?:Function):void => {
+        this.$scope.selectedZoneInstance.forceSave.next(afterSaveFunction);
+        this.eventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
+    }
+
+    private openUpdateComponentInstanceNameModal = ():void => {
+
+        let modalConfig:IModalConfig = {
+            title: "Edit Name",
+            size: "sm",
+            type: "custom",
+            testId: "renameInstanceModal",
+            buttons: [
+                {id: 'saveButton', text: 'OK', size: 'xsm', callback: this.saveInstanceName, closeModal: false},
+                {id: 'cancelButton', text: 'Cancel', size: 'sm', closeModal: true} 
+            ]
+        };
+
+        this.ModalServiceSdcUI.openCustomModal(modalConfig, ValueEditComponent, {name: this.$scope.currentComponent.selectedInstance.name, validityChangedCallback: this.enableOrDisableSaveButton});
+
+    };
+
+
+    private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
+        let saveButton: ModalButtonComponent = this.ModalServiceSdcUI.getCurrentInstance().getButtonById('saveButton');
+        saveButton.disabled = !shouldEnable;
+    }
+
+    private saveInstanceName = () => {
+        let currentModal = this.ModalServiceSdcUI.getCurrentInstance();
+        let nameFromModal:string = currentModal.innerModalContent.instance.name;
+
+        if(nameFromModal != this.$scope.currentComponent.selectedInstance.name){
+            currentModal.buttons[0].disabled = true;
+            let componentInstanceModel:ComponentInstance = ComponentInstanceFactory.createComponentInstance(this.$scope.currentComponent.selectedInstance);
+            componentInstanceModel.name = nameFromModal;
+
+            let onFailed = (error) => {
+                currentModal.buttons[0].disabled = false;
+            };
+            let onSuccess = (componentInstance:ComponentInstance) => {
+
+                this.$scope.currentComponent.selectedInstance.name = componentInstance.name;
+                //update requirements and capabilities owner name
+                _.forEach(this.$scope.currentComponent.selectedInstance.requirements, (requirementsArray:Array<Requirement>) => {
+                    _.forEach(requirementsArray, (requirement:Requirement):void => {
+                        requirement.ownerName = componentInstance.name;
+                    });
+                });
+
+                _.forEach(this.$scope.currentComponent.selectedInstance.capabilities, (capabilitiesArray:Array<Capability>) => {
+                    _.forEach(capabilitiesArray, (capability:Capability):void => {
+                        capability.ownerName = componentInstance.name;
+                    });
+                });
+                this.ModalServiceSdcUI.closeModal();
+                this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_COMPONENT_INSTANCE_NAME_CHANGED, this.$scope.currentComponent.selectedInstance);
+            };
+
+            this.$scope.currentComponent.updateComponentInstance(componentInstanceModel).then(onSuccess, onFailed);
+        }  else {
+            this.ModalServiceSdcUI.closeModal();
+        }
+        
     };
 
     private removeSelectedComponentInstance = ():void => {
@@ -151,6 +283,12 @@ export class CompositionViewModel {
         this.$scope.selectedComponent = this.$scope.currentComponent;
     };
 
+    private removeSelectedZoneInstance = ():void => {
+        this.$scope.currentComponent.selectedInstance = null;
+        this.$scope.selectedZoneInstance = null;
+        this.$scope.selectedComponent = this.$scope.currentComponent;
+    }
+
     private updateUuidMap = ():void => {
         /**
          * In case user press F5, the page is refreshed and this.sharingService.currentEntity will be undefined,
@@ -165,6 +303,7 @@ export class CompositionViewModel {
         this.$scope.sdcMenu = this.sdcMenu;
         this.$scope.isLoading = false;
         this.$scope.isLoadingRightPanel = false;
+        this.$scope.isCanvasTagging = false;
         this.$scope.graphApi = {};
         this.$scope.version = this.cacheService.get('version');
         this.initComponent();
@@ -175,6 +314,21 @@ export class CompositionViewModel {
             return this.$scope.currentComponent && this.$scope.currentComponent.selectedInstance != undefined && this.$scope.currentComponent.selectedInstance != null;
         };
 
+        this.$scope.$on('$destroy', () => {
+            this.unRegisterGraphEvents(this.$scope);
+        })
+
+        this.$scope.restoreComponent = ():void => {
+            this.ComponentServiceNg2.restoreComponent(this.$scope.selectedComponent.componentType, this.$scope.selectedComponent.uniqueId).subscribe(() => {
+                    this.Notification.success({
+                        message: '&lt;' + this.$scope.component.name + '&gt; ' + this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TEXT"),
+                        title: this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TITLE")
+                    });
+                    this.$scope.selectedComponent.archived = false;
+                }
+            )
+        };
+
         this.$scope.updateSelectedComponent = ():void => {
             if (this.$scope.currentComponent.selectedInstance) {
                 let parentComponentUid = this.$scope.currentComponent.selectedInstance.componentUid
@@ -215,15 +369,25 @@ export class CompositionViewModel {
 
             this.$log.debug('composition-view-model::onNodeSelected:: with id: ' + selectedComponent.uniqueId);
             this.$scope.currentComponent.setSelectedInstance(selectedComponent);
+            this.$scope.selectedZoneInstance = null;
             this.$scope.updateSelectedComponent();
 
+
+
+
             if (this.$state.current.name === 'workspace.composition.api') {
                 this.$state.go('workspace.composition.details');
             }
         };
 
+        this.$scope.setSelectedZoneInstance = (zoneInstance: ZoneInstance): void => {
+            this.$scope.currentComponent.selectedInstance = null;
+            this.$scope.selectedZoneInstance = zoneInstance;
+        };
+
         this.$scope.onBackgroundClick = ():void => {
             this.$scope.currentComponent.selectedInstance = null;
+            this.$scope.selectedZoneInstance = null;
             this.$scope.selectedComponent = this.$scope.currentComponent;
 
             if (this.$state.current.name === 'workspace.composition.api') {
@@ -238,6 +402,10 @@ export class CompositionViewModel {
         this.$scope.openUpdateModal = ():void => {
             this.openUpdateComponentInstanceNameModal();
         };
+
+        this.$scope.changeZoneInstanceName = (newName:string):void => {
+            this.$scope.selectedZoneInstance.instanceData.name = newName;
+        };
     
         this.$scope.deleteSelectedComponentInstance = ():void => {
             const {currentComponent} = this.$scope;
@@ -258,8 +426,7 @@ export class CompositionViewModel {
                     modalText += `<p>The following service paths will be erased: ${pathNames}</p>`;
                 }
             }
-
-            this.ModalsHandler.openAlertModal(title, modalText).then(this.removeSelectedComponentInstance);
+            this.ModalServiceSdcUI.openAlertModal(title, modalText, "OK", this.removeSelectedComponentInstance, "deleteInstanceModal");
         };
 
         this.$scope.openVersionChangeModal = (pathsToDelete:string[]):ng.IPromise<any> => {
@@ -308,7 +475,7 @@ export class CompositionViewModel {
             this.$scope.disabledTabs = state;
         };
 
-        this.eventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.$scope.reload);
+        this.eventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload);
 
     }
 }