7bed071d7edee61823f3f22587a189f508584451
[sdc.git] / catalog-ui / src / app / view-models / workspace / workspace-view-model.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 /**
22  * Created by obarda on 3/30/2016.
23  */
24 'use strict';
25 import * as _ from 'lodash';
26 import {
27     IUserProperties,
28     IAppMenu,
29     Resource,
30     Service, 
31     Component,
32     Plugin,
33     PluginsConfiguration,
34     PluginDisplayOptions
35 } from 'app/models';
36 import {
37     MenuItem, ModalsHandler, States, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ResourceType, PREVIOUS_CSAR_COMPONENT,
38     WorkspaceMode, ComponentFactory, ChangeLifecycleStateHandler, Role, ComponentState, MenuItemGroup, MenuHandler
39 } from 'app/utils';
40 import {
41     EventListenerService,
42     LeftPaletteLoaderService,
43     ProgressService
44 } from 'app/services';
45 import {
46     CacheService
47 } from 'app/services-ng2';
48 import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular';
49 import { AutomatedUpgradeService } from '../../ng2/pages/automated-upgrade/automated-upgrade.service';
50 import { CatalogService } from '../../ng2/services/catalog.service';
51 import { ComponentServiceNg2 } from '../../ng2/services/component-services/component.service';
52 import { EventBusService } from '../../ng2/services/event-bus.service';
53 import { HomeService } from '../../ng2/services/home.service';
54 import { PluginsService } from '../../ng2/services/plugins.service';
55 import { IDependenciesServerResponse } from '../../ng2/services/responses/dependencies-server-response';
56 import { WorkspaceNg1BridgeService } from '../../ng2/pages/workspace/workspace-ng1-bridge-service';
57 import { WorkspaceService } from '../../ng2/pages/workspace/workspace.service';
58
59 export interface IWorkspaceViewModelScope extends ng.IScope {
60
61     isLoading: boolean;
62     isCreateProgress: boolean;
63     component: Component;
64     originComponent: Component;
65     componentType: string;
66     importFile: any;
67     leftBarTabs: MenuItemGroup;
68     isNew: boolean;
69     isFromImport: boolean;
70     isValidForm: boolean;
71     isActiveTopBar: boolean;
72     mode: WorkspaceMode;
73     breadcrumbsModel: Array<MenuItemGroup>;
74     sdcMenu: IAppMenu;
75     changeLifecycleStateButtons: any;
76     version: string;
77     versionsList: Array<any>;
78     changeVersion: any;
79     isComposition: boolean;
80     isDeployment: boolean;
81     isPlugins: boolean;
82     $state: ng.ui.IStateService;
83     user: IUserProperties;
84     thirdParty: boolean;
85     disabledButtons: boolean;
86     menuComponentTitle: string;
87     progressService: ProgressService;
88     progressMessage: string;
89     ComponentServiceNg2: ComponentServiceNg2;
90     // leftPanelComponents:Array<Models.Components.Component>; //this is in order to load the left panel once, and not wait long time when moving to composition
91     unsavedChanges: boolean;
92     unsavedChangesCallback: Function;
93     unsavedFile: boolean;
94     hasNoDependencies: boolean;
95     models: Array<string>;
96
97     startProgress(message: string): void;
98     stopProgress(): void;
99     updateBreadcrumbs(component: Component): void;
100     updateUnsavedFileFlag(isUnsaved: boolean): void;
101     showChangeStateButton(): boolean;
102     getComponent(): Component;
103     setComponent(component: Component): void;
104     setOriginComponent(component: Component): void;
105     onMenuItemPressed(state: string, params: any): ng.IPromise<boolean>;
106     create(): void;
107     save(): Promise<void>;
108     setValidState(isValid: boolean): void;
109     changeLifecycleState(state: string): void;
110     handleChangeLifecycleState(state: string, newCsarVersion?: string, errorFunction?: Function): void;
111     disableMenuItems(): void;
112     enableMenuItems(): void;
113     isDesigner(): boolean;
114     isViewMode(): boolean;
115     isEditMode(): boolean;
116     isCreateMode(): boolean;
117     isDisableMode(): boolean;
118     isGeneralView(): boolean;
119     goToBreadcrumbHome(): void;
120     onVersionChanged(selectedId: string): void;
121     getLatestVersion(): void;
122     getStatus(): string;
123     showLifecycleIcon(): boolean;
124     updateSelectedMenuItem(state: string): void;
125     isSelected(menuItem: MenuItem): boolean;
126     uploadFileChangedInGeneralTab(): void;
127     updateMenuComponentName(ComponentName: string): void;
128     getTabTitle(): string;
129     reload(component: Component): void;
130 }
131
132 export class WorkspaceViewModel {
133
134     static '$inject' = [
135         '$scope',
136         'injectComponent',
137         'ComponentFactory',
138         '$state',
139         'sdcMenu',
140         '$q',
141         'MenuHandler',
142         'Sdc.Services.CacheService',
143         'ChangeLifecycleStateHandler',
144         'LeftPaletteLoaderService',
145         '$filter',
146         'EventListenerService',
147         'Notification',
148         '$stateParams',
149         'HomeService',
150         'CatalogService',
151         'Sdc.Services.ProgressService',
152         'ComponentServiceNg2',
153         'AutomatedUpgradeService',
154         'EventBusService',
155         'ModalServiceSdcUI',
156         'PluginsService',
157         'WorkspaceNg1BridgeService',
158         'workspaceService'
159     ];
160
161     constructor(private $scope: IWorkspaceViewModelScope,
162                 private injectComponent: Component,
163                 private ComponentFactory: ComponentFactory,
164                 private $state: ng.ui.IStateService,
165                 private sdcMenu: IAppMenu,
166                 private $q: ng.IQService,
167                 private MenuHandler: MenuHandler,
168                 private cacheService: CacheService,
169                 private ChangeLifecycleStateHandler: ChangeLifecycleStateHandler,
170                 private LeftPaletteLoaderService: LeftPaletteLoaderService,
171                 private $filter: ng.IFilterService,
172                 private EventListenerService: EventListenerService,
173                 private Notification: any,
174                 private $stateParams: any,
175                 private homeService: HomeService,
176                 private catalogService: CatalogService,
177                 private progressService: ProgressService,
178                 private ComponentServiceNg2: ComponentServiceNg2,
179                 private AutomatedUpgradeService: AutomatedUpgradeService,
180                 private eventBusService: EventBusService,
181                 private modalServiceSdcUI: SdcUiServices.ModalService,
182                 private pluginsService: PluginsService,
183                 private workspaceNg1BridgeService: WorkspaceNg1BridgeService,
184                 private workspaceService: WorkspaceService) {
185
186                 this.initScope();
187                 // this.initAfterScope();
188                 this.$scope.updateSelectedMenuItem(this.$state.current.name);
189     }
190
191     private role: string;
192     private category: string;
193     private components: Component[];
194     
195     private initViewMode = ():WorkspaceMode => {
196         let mode = WorkspaceMode.VIEW;
197
198         if (!this.$state.params['id']) {   //&& !this.$state.params['vspComponent']
199             mode = WorkspaceMode.CREATE;
200         } else {
201             if (this.$scope.component.lifecycleState === ComponentState.NOT_CERTIFIED_CHECKOUT &&
202                 this.$scope.component.lastUpdaterUserId === this.cacheService.get('user').userId) {
203                 if ((this.$scope.component.isService() || this.$scope.component.isResource()) && this.role === Role.DESIGNER) {
204                     mode = WorkspaceMode.EDIT;
205                 }
206             }
207         }
208         this.workspaceNg1BridgeService.updateIsViewOnly(mode === WorkspaceMode.VIEW);
209         return mode;
210     }
211
212     private initChangeLifecycleStateButtons = (): void => {
213         let state: string;
214         if (this.$scope.component.isService() && this.$scope.component.lifecycleState === 'CERTIFIED') {
215             state = this.$scope.component.distributionStatus;
216         } else {
217             state = this.$scope.component.lifecycleState;
218         }
219         this.$scope.changeLifecycleStateButtons = (this.sdcMenu.roles[this.role].changeLifecycleStateButtons[state] || [])[this.$scope.component.componentType.toUpperCase()];
220     }
221
222     private initScope = (): void => {
223         this.$scope.component = this.injectComponent;
224         this.$scope.menuComponentTitle = this.$scope.component.name;
225         this.$scope.disabledButtons = false;
226         this.$scope.originComponent = this.ComponentFactory.createComponent(this.$scope.component);
227         this.$scope.componentType = this.$scope.component.componentType;
228         this.$scope.version = this.cacheService.get('version');
229         this.$scope.user = this.cacheService.get('user');
230         this.role = this.$scope.user.role;
231         this.category = this.$scope.component.selectedCategory;
232         this.$scope.mode = this.initViewMode();
233         this.$scope.isValidForm = true;
234         this.initChangeLifecycleStateButtons();
235         this.initVersionObject();
236         this.$scope.$state = this.$state;
237         this.$scope.isLoading = false;
238         this.$scope.isComposition = (this.$state.current.name.indexOf(States.WORKSPACE_COMPOSITION) > -1);
239         this.$scope.isDeployment = this.$state.current.name == States.WORKSPACE_DEPLOYMENT;
240         this.$scope.progressService = this.progressService;
241         this.$scope.unsavedChanges = false;
242
243         this.$scope.hasNoDependencies = true;
244         this.verifyIfDependenciesExist();
245
246         this.EventListenerService.registerObserverCallback(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.setWorkspaceButtonState);
247         this.$scope.getComponent = (): Component => {
248             return this.$scope.component;
249         };
250
251         this.$scope.updateMenuComponentName = (ComponentName:string):void => {
252             this.$scope.menuComponentTitle = ComponentName;
253         };
254
255         this.$scope.sdcMenu = this.sdcMenu;
256         // Will be called from each step after save to update the resource.
257         this.$scope.setComponent = (component:Component):void => {
258             this.$scope.component = component;
259         };
260
261         this.$scope.setOriginComponent = (component:Component):void => {
262             this.$scope.originComponent = component;
263         }
264
265         this.$scope.uploadFileChangedInGeneralTab = ():void => {
266             // In case user select browse file, and in update mode, need to disable submit for testing and checkin buttons.
267             if (this.$scope.isEditMode() && this.$scope.component.isResource() && (<Resource>this.$scope.component).resourceType == ResourceType.VF) {
268                 // NOTE: Commented out the disabling of the workspace buttons on CSAR updating due fix of a bug [417534]
269                 // this.$scope.disabledButtons = true;
270             }
271         };
272
273         this.$scope.archiveComponent = ():void => {
274             this.$scope.isLoading = true;
275             const typeComponent = this.$scope.component.componentType;
276             this.ComponentServiceNg2.archiveComponent(typeComponent, this.$scope.component.uniqueId).subscribe(()=> {
277                 this.$scope.isLoading = false;
278                 if (this.$state.params.previousState) {
279                     switch (this.$state.params.previousState) {
280                         case 'catalog':
281                         case 'dashboard':
282                             this.$state.go(this.$state.params.previousState);
283                             break;
284                         default:
285                             break;
286                     }
287                 }
288                 this.$scope.component.isArchived = true;
289                 this.deleteArchiveCache();
290
291                 this.Notification.success({
292                     message: this.$scope.component.name + ' ' + this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TEXT"),
293                     title: this.$filter('translate')("ARCHIVE_SUCCESS_MESSAGE_TITLE")
294                 });
295             }, (error) => { this.$scope.isLoading = false; });
296         }
297
298         this.$scope.restoreComponent = ():void => {
299             this.$scope.isLoading = true;
300             const typeComponent = this.$scope.component.componentType;
301             this.ComponentServiceNg2.restoreComponent(typeComponent, this.$scope.component.uniqueId).subscribe(()=> {
302                 this.$scope.isLoading = false;
303                 this.Notification.success({
304                     message: this.$scope.component.name + ' ' + this.$filter('translate')("RESTORE_SUCCESS_MESSAGE_TEXT"),
305                     title: this.$filter('translate')("RESTORE_SUCCESS_MESSAGE_TITLE")
306                 });
307                 this.$scope.reload(this.$scope.component);
308             });
309             this.$scope.component.isArchived = false;
310             this.deleteArchiveCache();
311         }
312
313         this.$scope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams) => {
314             if(this.$scope.isEditMode()){
315                 if (fromParams.id == toParams.id && this.$state.current.data && this.$state.current.data.unsavedChanges) {
316                     event.preventDefault();
317                     if(this.$scope.isValidForm){
318                         this.$scope.save().then(() => {
319                             this.$scope.onMenuItemPressed(toState.name, toParams);
320                         }, ()=> {
321                             console.error("Save failed, unable to navigate to " + toState.name);
322                         })
323                     } else {
324                         console.error("Form is invalid, unable to navigate to " + toState.name);
325                     }
326                 }
327             }
328
329         });
330
331         this.$scope.$on('$stateChangeSuccess', (event, toState) => {
332             this.$scope.updateSelectedMenuItem(this.$state.current.name);
333         });
334
335         this.$scope.onMenuItemPressed = (state:string, params:any):ng.IPromise<boolean> => {
336
337             let deferred:ng.IDeferred<boolean> = this.$q.defer();
338             let goToState = ():void => {
339                 this.$state.go(state, Object.assign({
340                     id: this.$scope.component.uniqueId,
341                     type: this.$scope.component.componentType.toLowerCase(),
342                     components: this.components
343                 }, params));
344                 deferred.resolve(true);
345             };
346
347             if (this.$scope.isEditMode() && //this is a workaround for amdocs - we need to get the artifact in order to avoid saving the vf when moving from their tabs
348                 (this.$state.current.name === States.WORKSPACE_MANAGEMENT_WORKFLOW || this.$state.current.name === States.WORKSPACE_NETWORK_CALL_FLOW)) {
349                 let onGetSuccess = (component:Component) => {
350                     this.$scope.isLoading = false;
351                     // Update the components
352                     this.$scope.component = component;
353                     goToState();
354                 };
355                 let onFailed = () => {
356                     this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_ERROR);
357                     this.$scope.isLoading = false; // stop the progress.
358                     deferred.reject(false);
359                 };
360                 this.$scope.component.getComponent().then(onGetSuccess, onFailed);
361             } else {
362                 goToState();
363             }
364             return deferred.promise;
365         };
366
367         this.$scope.setValidState = (isValid:boolean):void => {
368             this.$scope.isValidForm = isValid;
369         };
370
371         this.$scope.onVersionChanged = (selectedId:string):void => {
372             if (this.$scope.isGeneralView() && this.$state.current.data.unsavedChanges) {
373                 this.$scope.changeVersion.selectedVersion = _.find(this.$scope.versionsList, (versionObj)=> {
374                     return versionObj.versionId === this.$scope.component.uniqueId;
375                 });
376             }
377
378             let eventData = {
379                 uuid: this.$scope.component.uuid,
380                 version: this.$scope.changeVersion.selectedVersion.versionNumber
381             };
382
383             this.eventBusService.notify("VERSION_CHANGED", eventData).subscribe(() => {
384                 this.$scope.isLoading = true;
385
386                 this.$state.go(this.$state.current.name, {
387                     id: selectedId,
388                     type: this.$scope.componentType.toLowerCase(),
389                     mode: WorkspaceMode.VIEW,
390                     components: this.$state.params['components']
391                 }, {reload: true});
392             });
393         };
394
395         this.$scope.getLatestVersion = ():void => {
396             this.$scope.onVersionChanged(_.first(this.$scope.versionsList).versionId);
397         };
398
399         this.$scope.create = () => {
400
401             this.$scope.startProgress("Creating Asset...");
402             _.first(this.$scope.leftBarTabs.menuItems).isDisabled = true;//disabled click on general tab (DE246274)
403
404              // In case we import CSAR. Notify user that import VF will take long time (the create is performed in the background).
405              if (this.$scope.component.isResource() && (<Resource>this.$scope.component).csarUUID) {
406                 this.Notification.info({
407                     message: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_DESCRIPTION"),
408                     title: this.$filter('translate')("IMPORT_VF_MESSAGE_CREATE_TAKES_LONG_TIME_TITLE")
409                 });
410             }
411
412             let onFailed = () => {
413                 this.$scope.stopProgress();
414                 this.$scope.isLoading = false; // stop the progress.
415                 _.first(this.$scope.leftBarTabs.menuItems).isDisabled = false;//enabled click on general tab (DE246274)
416                 this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_ERROR);
417                 let modalInstance:ng.ui.bootstrap.IModalServiceInstance;
418                 modalInstance && modalInstance.close();  // Close the modal in case it is opened.
419                 this.$scope.component.tags = _.without(this.$scope.component.tags, this.$scope.component.name);// for fix DE246217
420
421                 this.$scope.setValidState(true);  // Set the form valid (if sent form is valid, the error from server).
422             };
423
424             let onSuccessCreate = (component:Component) => {
425
426                 this.$scope.stopProgress();
427                 this.showSuccessNotificationMessage();
428
429                 // Update the components list for breadcrumbs
430                 this.components.unshift(component);
431
432                 this.$state.go(States.WORKSPACE_GENERAL, {
433                     id: component.uniqueId,
434                     type: component.componentType.toLowerCase(),
435                     components: this.components
436                 }, {inherit: false});
437             };
438             
439             console.log(this.$scope.component, "this.$scope.component")
440             if ((<Service>this.$scope.component).serviceType == "Service") {
441                 this.ComponentFactory.importComponentOnServer(this.$scope.component).then(onSuccessCreate, onFailed);
442             } else {
443                 this.ComponentFactory.createComponentOnServer(this.$scope.component).then(onSuccessCreate, onFailed);
444             }
445
446
447
448         };
449
450         this.$scope.save = ():Promise<void> => {
451
452             this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_CLICK);
453
454             this.$scope.startProgress("Updating Asset...");
455             this.$scope.disableMenuItems();
456
457             return new Promise<void>((resolve, reject) => {
458                 let stopProgressAndEnableUI = () => {
459                     this.$scope.disabledButtons = false;
460                     this.$scope.isLoading = false;
461                     this.$scope.enableMenuItems();
462                     this.$scope.stopProgress();
463                 }
464
465                 let onFailed = () => {
466                     stopProgressAndEnableUI();
467                     this.$scope.updateUnsavedFileFlag(true);
468                     this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_SAVE_BUTTON_ERROR);
469
470                     reject();
471                 };
472
473                 let onSuccessUpdate = (component:Component) => {
474                     stopProgressAndEnableUI();
475                     this.showSuccessNotificationMessage();
476
477                     component.tags = _.reject(component.tags, (item)=> {
478                         return item === component.name
479                     });
480
481                     this.$scope.updateBreadcrumbs(component);
482
483                     //update the component
484                     this.$scope.setComponent(component);
485                     this.$scope.originComponent = this.ComponentFactory.createComponent(this.$scope.component);
486
487                     if (this.cacheService.contains(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) {
488                         this.cacheService.remove(CHANGE_COMPONENT_CSAR_VERSION_FLAG);
489                     }
490                     if (this.cacheService.contains(PREVIOUS_CSAR_COMPONENT)) {
491                         this.cacheService.remove(PREVIOUS_CSAR_COMPONENT);
492                     }
493
494                     //clear edit flags
495                     this.$state.current.data.unsavedChanges = false;
496                     this.$scope.unsavedFile = false;
497                     this.$scope.reload(component);
498                     resolve();
499                 };
500
501                 this.$scope.component.updateComponent().then(onSuccessUpdate, onFailed);
502             });
503
504         };
505
506         this.$scope.changeLifecycleState = (state:string):void => {
507             if (this.$scope.isGeneralView() && state !== 'deleteVersion') {
508                 this.EventListenerService.notifyObservers(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, state);
509             } else {
510                 this.$scope.handleChangeLifecycleState(state);
511             }
512         };
513
514         let defaultActionAfterChangeLifecycleState = ():void => {
515             if (this.$state.current.data && this.$state.current.data.unsavedChanges) {
516                 this.$state.current.data.unsavedChanges = false;
517             }
518             this.$state.go('dashboard');
519         };
520
521         this.$scope.handleChangeLifecycleState = (state:string, newCsarVersion?:string, onError?: Function) => {
522             if ('monitor' === state) {
523                 this.$state.go('workspace.distribution');
524                 return;
525             }
526
527             let data = this.$scope.changeLifecycleStateButtons[state];
528             if (!data && this.$stateParams.componentCsar && !this.$scope.isCreateMode()) {
529                 data = {text: 'Check Out', url: 'lifecycleState/CHECKOUT'};
530             }
531             const onSuccess = (component, url:string):void => {
532                 // Updating the component from server response
533  
534                 // Creating the data object to notify the plugins with
535                 const eventData: any = {
536                     uuid: this.$scope.component.uuid,
537                     version: this.$scope.component.version
538                 };
539
540                 // the server returns only metaData (small component) except checkout (Full component)  ,so we update only the statuses of distribution & lifecycle
541                 this.$scope.component.lifecycleState = component.lifecycleState;
542                 this.$scope.component.distributionStatus = component.distributionStatus;
543
544                 switch (url) {
545                     case 'lifecycleState/CHECKOUT':
546                         this.workspaceNg1BridgeService.updateIsViewOnly(false);
547                         this.eventBusService.notify("CHECK_OUT", eventData, false).subscribe(() => {
548                             // only checkOut get the full component from server
549                             //   this.$scope.component = component;
550                             // Work around to change the csar version
551                             if(newCsarVersion) {
552                                 this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, newCsarVersion);
553                                 (this.$scope.component as Resource).csarVersion = newCsarVersion;
554                             }
555
556                             //when checking out a minor version uuid remains
557                             const bcIdx = _.findIndex(this.components, (item) => {
558                                 return item.uuid === component.uuid;
559                             });
560                             if (bcIdx !== -1) {
561                                 this.components[bcIdx] = component;
562                             } else {
563                                 //when checking out a major(certified) version
564                                 this.components.unshift(component);
565                             }
566                             this.$scope.mode = this.initViewMode();
567                             this.initChangeLifecycleStateButtons();
568                             this.initVersionObject();
569                             this.$scope.isLoading = false;
570                             this.EventListenerService.notifyObservers(EVENTS.ON_CHECKOUT, component);
571                             this.workspaceService.setComponentMetadata(component.componentMetadata);
572
573                             this.Notification.success({
574                                 message: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TEXT"),
575                                 title: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TITLE")
576                             });
577
578                         });
579                         break;
580                     case 'lifecycleState/CHECKIN':
581                         this.workspaceNg1BridgeService.updateIsViewOnly(true);
582                         defaultActionAfterChangeLifecycleState();
583                         this.Notification.success({
584                             message: this.$filter('translate')("CHECKIN_SUCCESS_MESSAGE_TEXT"),
585                             title: this.$filter('translate')("CHECKIN_SUCCESS_MESSAGE_TITLE")
586                         });
587                         break;
588                     case 'lifecycleState/UNDOCHECKOUT':
589                         this.eventBusService.notify("UNDO_CHECK_OUT", eventData, false).subscribe(() => {
590                             defaultActionAfterChangeLifecycleState();
591                             this.Notification.success({
592                                 message: this.$filter('translate')("DELETE_SUCCESS_MESSAGE_TEXT"),
593                                 title: this.$filter('translate')("DELETE_SUCCESS_MESSAGE_TITLE")
594                             });
595                         });
596                         break;
597                     case 'lifecycleState/certify':
598                         this.$scope.handleCertification(component);
599                         this.verifyIfDependenciesExist();
600                         this.$scope.reload(component);
601                         break;
602                     case 'distribution/PROD/activate':
603                         this.Notification.success({
604                             message: this.$filter('translate')("DISTRIBUTE_SUCCESS_MESSAGE_TEXT"),
605                             title: this.$filter('translate')("DISTRIBUTE_SUCCESS_MESSAGE_TITLE")
606                         });
607                         this.initChangeLifecycleStateButtons();
608                         break;
609                     default :
610                         defaultActionAfterChangeLifecycleState();
611                 }
612                 if (data.url !== 'lifecycleState/CHECKOUT') {
613                     this.$scope.isLoading = false;
614                 }
615             };
616             this.ChangeLifecycleStateHandler.changeLifecycleState(this.$scope.component, data, this.$scope, onSuccess);
617         };
618
619         this.$scope.deleteArchivedComponent = (): void => {
620             const modalTitle: string = this.$filter('translate')("COMPONENT_VIEW_DELETE_MODAL_TITLE");
621             const modalMessage: string = this.$filter('translate')("COMPONENT_VIEW_DELETE_MODAL_TEXT");
622             const modalButton = {
623                 testId: 'ok-button',
624                 text: this.sdcMenu.alertMessages.okButton,
625                 type: SdcUiCommon.ButtonType.warning,
626                 callback: this.$scope.handleDeleteArchivedComponent,
627                 closeModal: true
628             } as SdcUiComponents.ModalButtonComponent;
629             this.modalServiceSdcUI.openWarningModal(modalTitle, modalMessage, 'alert-modal', [modalButton]);
630         };
631
632         this.$scope.handleDeleteArchivedComponent = (): void => {
633             this.$scope.isLoading = true;
634             const typeComponent = this.$scope.component.componentType;
635             this.ComponentServiceNg2.deleteComponent(typeComponent, this.$scope.component.uniqueId).subscribe(()=> {
636                 this.deleteArchiveCache();
637                 this.Notification.success({
638                     message: this.$scope.component.name + ' ' + this.$filter('translate')("DELETE_SUCCESS_MESSAGE_TEXT"),
639                     title: this.$filter('translate')("DELETE_SUCCESS_MESSAGE_TITLE")
640                 });
641                 if (this.$state.params.previousState) {
642                     switch (this.$state.params.previousState) {
643                         case 'catalog':
644                         case 'dashboard':
645                             this.$state.go(this.$state.params.previousState);
646                             break;
647                         default:
648                             this.$state.go('dashboard');
649                             break;
650                     }
651                 }
652                 this.$scope.isLoading = false;
653             }, () => {
654                 this.Notification.error({
655                     message: this.$scope.component.name + ' ' + this.$filter('translate')('DELETE_FAILURE_MESSAGE_TEXT'),
656                     title: this.$filter('translate')('DELETE_FAILURE_MESSAGE_TITLE')
657                 });
658                 this.$scope.isLoading = false;
659             });
660         };
661
662         this.$scope.isViewMode = ():boolean => {
663             return this.$scope.mode === WorkspaceMode.VIEW;
664         };
665
666         this.$scope.isDesigner = ():boolean => {
667             return this.role == Role.DESIGNER;
668         };
669
670         this.$scope.isDisableMode = ():boolean => {
671             return this.$scope.mode === WorkspaceMode.VIEW && this.$scope.component.lifecycleState === ComponentState.NOT_CERTIFIED_CHECKIN;
672         };
673
674         this.$scope.isGeneralView = ():boolean => {
675             //we show revert and save icons only in general view
676             return this.$state.current.name === States.WORKSPACE_GENERAL;
677         };
678
679         this.$scope.isCreateMode = ():boolean => {
680             return this.$scope.mode === WorkspaceMode.CREATE;
681         };
682
683         this.$scope.checkDisableButton = (button: any):boolean => {
684             // Logic moved from html to component
685             if (this.$scope.isCreateMode() || button.disabled || this.$scope.disabledButtons || !this.$scope.isValidForm || this.$scope.unsavedChanges || this.$scope.component.isArchived){
686                 return true;
687             }
688
689             // Specific verification for Checkout - enabled only in case the component is the latest version.
690             let result: boolean = false;
691
692             if (button.url === 'lifecycleState/CHECKOUT') {
693                 result = !this.$scope.component.isLatestVersion();
694             }
695             return result;
696         };
697
698         this.$scope.isEditMode = ():boolean => {
699             return this.$scope.mode === WorkspaceMode.EDIT;
700         };
701
702         this.$scope.goToBreadcrumbHome = ():void => {
703             let bcHome:MenuItemGroup = this.$scope.breadcrumbsModel[0];
704             this.$state.go(bcHome.menuItems[bcHome.selectedIndex].state);
705         };
706
707         this.$scope.showLifecycleIcon = ():boolean => {
708             return this.role == Role.DESIGNER;
709         };
710
711         this.$scope.getStatus = ():string => {
712             if (this.$scope.isCreateMode()) {
713                 return 'IN DESIGN';
714             }
715
716             return this.$scope.component.getStatus(this.sdcMenu);
717         };
718
719         this.initMenuItems();
720
721         this.$scope.showLatestVersion = (): boolean => {
722             let result: boolean = true;
723             if (!this.$scope.component.isLatestVersion()) {
724                 result = false;
725             }
726             if (ComponentState.NOT_CERTIFIED_CHECKOUT === this.$scope.component.lifecycleState && this.$scope.isViewMode()) {
727                 result = false;
728             }
729             return result;
730         };
731
732         this.$scope.updateSelectedMenuItem = (state:string):void => {
733             let stateArray:Array<string> = state.split('.', 2);
734             let stateWithoutInternalNavigate:string = stateArray[0] + '.' + stateArray[1];
735             let selectedItem:MenuItem = _.find(this.$scope.leftBarTabs.menuItems, (item:MenuItem) => {
736                 let itemStateArray:Array<string> = item.state.split('.', 2);
737                 let itemStateWithoutNavigation:string = itemStateArray[0] + '.' + itemStateArray[1];
738                 return (itemStateWithoutNavigation === stateWithoutInternalNavigate);
739             });
740
741             let selectedIndex = selectedItem ? this.$scope.leftBarTabs.menuItems.indexOf(selectedItem) : 0;
742
743             if (stateArray[1] === 'plugins') {
744                 _.forEach(PluginsConfiguration.plugins, (plugin) => {
745                     if (plugin.pluginStateUrl == this.$state.params.path) {
746                         return false;
747                     }
748                     else if (this.pluginsService.isPluginDisplayedInContext(plugin, this.role, this.$scope.component.getComponentSubType())) {
749                         selectedIndex++;
750                     }
751                 });
752             }
753
754             this.$scope.leftBarTabs.selectedIndex = selectedIndex;
755         };
756
757         this.$scope.isSelected = (menuItem: MenuItem): boolean => {
758             return this.$scope.leftBarTabs.selectedIndex === _.indexOf(this.$scope.leftBarTabs.menuItems, menuItem);
759         };
760
761         this.$scope.$watch('$state.current.name', (newVal: string): void => {
762             if (newVal) {
763                 this.$scope.isComposition = (newVal.indexOf(States.WORKSPACE_COMPOSITION) > -1);
764                 this.$scope.isDeployment = newVal == States.WORKSPACE_DEPLOYMENT;
765                 this.$scope.isPlugins = newVal == States.WORKSPACE_PLUGINS;
766             }
767         });
768
769         this.$scope.getTabTitle = (): string => {
770             return this.$scope.leftBarTabs.menuItems.find((menuItem: MenuItem) => {
771                 return menuItem.state == this.$scope.$state.current.name;
772             }).text;
773         };
774
775         this.$scope.reload = (component: Component): void => {
776             const isGeneralTab = this.$state.current.name === 'workspace.general';
777             // nullify the componentCsar in case we are in general tab so we know we didnt came from updateVsp Modal
778             if (isGeneralTab) {
779                 this.$state.go(this.$state.current.name, {id: component.uniqueId, componentCsar: null}, {reload: true});
780             } else {
781                 this.$state.go(this.$state.current.name, {id: component.uniqueId}, {reload: true});
782             }
783         };
784
785         this.$scope.$on('$destroy', () => {
786             this.EventListenerService.unRegisterObserver(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES);
787         });
788
789         this.$scope.openAutomatedUpgradeModal = ():void => {
790             this.$scope.isLoading = true;
791             this.ComponentServiceNg2.getDependencies(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response:Array<IDependenciesServerResponse>)=> {
792                 this.$scope.isLoading = false;
793                 this.AutomatedUpgradeService.openAutomatedUpgradeModal(response, this.$scope.component, false);
794             });
795         }
796
797         this.$scope.handleCertification = (certifyComponent): void => {
798             if (this.$scope.component.getComponentSubType() === ResourceType.VF || this.$scope.component.isService()) {
799                 this.ComponentServiceNg2.getDependencies(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response:Array<IDependenciesServerResponse>) => {
800                     this.$scope.isLoading = false;
801
802                     const isUpgradeNeeded = _.filter(response, (componentToUpgrade:IDependenciesServerResponse) => {
803                         return componentToUpgrade.dependencies && componentToUpgrade.dependencies.length > 0;
804                     });
805                     if (isUpgradeNeeded.length === 0) {
806                         this.onSuccessWithoutUpgradeNeeded();
807                         return;
808                     }
809                     this.refreshDataAfterChangeLifecycleState(certifyComponent);
810                     this.AutomatedUpgradeService.openAutomatedUpgradeModal(response, this.$scope.component, true);
811                 });
812             } else {
813                 this.onSuccessWithoutUpgradeNeeded();
814             }
815         }
816
817         this.$scope.disableMenuItems = () => {
818             this.$scope.leftBarTabs.menuItems.forEach((item: MenuItem) => {
819                 item.isDisabled = (States.WORKSPACE_GENERAL !== item.state);
820             });
821         }
822
823         this.$scope.enableMenuItems = () => {
824             this.$scope.leftBarTabs.menuItems.forEach((item: MenuItem) => {
825                 item.isDisabled = false;
826             });
827         };
828
829
830         this.$scope.startProgress = (message: string): void => {
831             this.progressService.initCreateComponentProgress(this.$scope.component.uniqueId);
832             this.$scope.isCreateProgress = true;
833             this.$scope.progressMessage = message;
834         };
835
836         this.$scope.stopProgress = (): void => {
837             this.$scope.isCreateProgress = false;
838             this.progressService.deleteProgressValue(this.$scope.component.uniqueId);
839         }
840
841         this.$scope.updateBreadcrumbs = (component: Component): void => {
842             // Update the components list for breadcrumbs
843             const bcIdx = this.MenuHandler.findBreadcrumbComponentIndex(this.components, component);
844             if (bcIdx !== -1) {
845                 this.components[bcIdx] = component;
846                 this.initBreadcrumbs();  // re-calculate breadcrumbs
847             }
848         };
849
850         this.$scope.updateUnsavedFileFlag = (isUnsaved:boolean) => {
851             this.$scope.unsavedFile = isUnsaved;
852         };
853
854     }
855
856     private onSuccessWithoutUpgradeNeeded = (): void => {
857         this.$scope.isLoading = false;
858         this.Notification.success({
859             message: this.$filter('translate')('SERVICE_CERTIFICATION_STATUS_TEXT'),
860             title: this.$filter('translate')('SERVICE_CERTIFICATION_STATUS_TITLE')
861         });
862         this.initVersionObject();
863         this.initChangeLifecycleStateButtons();
864     }
865
866     private refreshDataAfterChangeLifecycleState = (component:Component):void => {
867         this.$scope.isLoading = false;
868         this.$scope.mode = this.initViewMode();
869         this.initChangeLifecycleStateButtons();
870         this.initVersionObject();
871         this.EventListenerService.notifyObservers(EVENTS.ON_LIFECYCLE_CHANGE, component);
872     }
873
874     private initAfterScope = (): void => {
875         // In case user select csar from the onboarding modal, need to disable checkout and submit for testing.
876         if (this.$state.params['disableButtons'] === true) {
877             this.$scope.uploadFileChangedInGeneralTab();
878         }
879     };
880
881     private initVersionObject = (): void => {
882         this.$scope.versionsList = (this.$scope.component.getAllVersionsAsSortedArray()).reverse();
883         this.$scope.changeVersion = {
884             selectedVersion: _.find(this.$scope.versionsList, (versionObj) => {
885                 return versionObj.versionId === this.$scope.component.uniqueId;
886             })
887         };
888     }
889
890     private getNewComponentBreadcrumbItem = (): MenuItem => {
891         let text = '';
892         if (this.$scope.component.isResource() && (<Resource>this.$scope.component).isCsarComponent()) {
893             text = this.$scope.component.getComponentSubType() + ': ' + this.$scope.component.name;
894         } else {
895             text = 'Create new ' + this.$state.params['type'];
896         }
897         return new MenuItem(text, null, States.WORKSPACE_GENERAL, 'goToState', [this.$state.params]);
898     }
899
900     private updateMenuItemByRole = (menuItems: any[], role: string) => {
901         const tempMenuItems: any[] = new Array<any>();
902         menuItems.forEach((item: any) => {
903             //remove item if role is disabled
904             if (!(item.disabledRoles && item.disabledRoles.indexOf(role) > -1)) {
905                 tempMenuItems.push(item);
906             }
907         });
908         return tempMenuItems;
909     }
910
911         private updateMenuItemByCategory = (menuItems:Array<any>, category:string) => {
912         let tempMenuItems:Array<any> = new Array<any>();
913         menuItems.forEach((item:any) => {
914             //update flag disabledCategory to true if category is disabled
915             item.disabledCategory = false;
916             if ((item.disabledCategories && item.disabledCategories.indexOf(category) > -1))
917             {
918                 item.disabledCategory = true;
919             }
920             tempMenuItems.push(item);
921         });
922         return tempMenuItems;
923     };
924
925
926     private deleteArchiveCache = () => {
927         this.cacheService.remove('archiveComponents'); // delete the cache to ensure the archive is reloaded from server
928     }
929
930     private initBreadcrumbs = () => {
931         this.components = this.cacheService.get('breadcrumbsComponents');
932         const breadcrumbsComponentsLvl = this.MenuHandler.generateBreadcrumbsModelFromComponents(this.components, this.$scope.component);
933
934         if (this.$scope.isCreateMode()) {
935             const createItem = this.getNewComponentBreadcrumbItem();
936             if (!breadcrumbsComponentsLvl.menuItems) {
937                 breadcrumbsComponentsLvl.menuItems = [];
938             }
939             breadcrumbsComponentsLvl.menuItems.unshift(createItem);
940             breadcrumbsComponentsLvl.selectedIndex = 0;
941         }
942
943         this.$scope.breadcrumbsModel = [breadcrumbsComponentsLvl, this.$scope.leftBarTabs];
944     }
945
946     private initMenuItems() {
947
948         const inCreateMode = this.$scope.isCreateMode();
949         this.$scope.leftBarTabs = new MenuItemGroup();
950         let menuItemsObjects: any[] = this.updateMenuItemByRole(this.sdcMenu.component_workspace_menu_option[this.$scope.component.getComponentSubType()], this.role);
951         if (this.$scope.component.getComponentSubType() === 'SERVICE') {
952             const menuItemsObjectsCategory: any[] = this.updateMenuItemByCategory(menuItemsObjects, this.category);
953             menuItemsObjects = menuItemsObjectsCategory;
954         }
955
956         // Only adding plugins to the workspace if they can be displayed for the current user role
957         _.each(PluginsConfiguration.plugins, (plugin: Plugin) => {
958             if (this.pluginsService.isPluginDisplayedInContext(plugin, this.role, this.$scope.component.getComponentSubType())) {
959                 menuItemsObjects.push({
960                     text: plugin.pluginDisplayOptions['context'].displayName,
961                     action: 'onMenuItemPressed',
962                     state: 'workspace.plugins',
963                     params: {path: plugin.pluginStateUrl}
964                 });
965             }
966         });
967
968         this.$scope.leftBarTabs.menuItems = menuItemsObjects.map((item: MenuItem) => {
969             const menuItem = new MenuItem(item.text, item.callback, item.state, item.action, item.params, item.blockedForTypes, item.disabledCategory);
970             if (menuItem.params) {
971                 menuItem.params.state = menuItem.state;
972             }
973             else {
974                 menuItem.params = {state: menuItem.state};
975             }
976             menuItem.callback = () => this.$scope[menuItem.action](menuItem.state, menuItem.params);
977             menuItem.isDisabled = (inCreateMode && States.WORKSPACE_GENERAL !== menuItem.state) ||
978                 (States.WORKSPACE_DEPLOYMENT === menuItem.state && this.$scope.component.modules
979                 && this.$scope.component.modules.length === 0 && this.$scope.component.isResource()) ||
980                 (menuItem.disabledCategory === true);
981             return menuItem;
982         });
983
984         if (this.cacheService.get('breadcrumbsComponents')) {
985             this.initBreadcrumbs();
986         }
987         else {
988             this.initBreadcrumbsComponents();
989         }
990     }
991
992     private showSuccessNotificationMessage = ():void => {
993         this.Notification.success({
994             message: this.$filter('translate')('IMPORT_VF_MESSAGE_CREATE_FINISHED_DESCRIPTION'),
995             title: this.$filter('translate')('IMPORT_VF_MESSAGE_CREATE_FINISHED_TITLE')
996         });
997     }
998
999     private setWorkspaceButtonState = (newState: boolean, callback?: Function) => {
1000         this.$scope.unsavedChanges = newState;
1001         this.$scope.unsavedChangesCallback = callback;
1002     }
1003
1004     private initBreadcrumbsComponents = (): void => {
1005         let breadcrumbsComponentsObservable;
1006         if (this.$stateParams.previousState === 'dashboard') {
1007             breadcrumbsComponentsObservable = this.homeService.getAllComponents(true);
1008         } else if (this.$stateParams.previousState === 'catalog') {
1009             breadcrumbsComponentsObservable = this.catalogService.getCatalog();
1010         } else {
1011             this.cacheService.remove('breadcrumbsComponentsState');
1012             this.cacheService.remove('breadcrumbsComponents');
1013             return;
1014         }
1015         breadcrumbsComponentsObservable.subscribe((components) => {
1016             this.cacheService.set('breadcrumbsComponentsState', this.$stateParams.previousState);
1017             this.cacheService.set('breadcrumbsComponents', components);
1018             this.initBreadcrumbs();
1019         });
1020
1021     }
1022
1023     private verifyIfDependenciesExist(): void {
1024         let containsDependencies = [];
1025         if (this.$scope.component.componentType && this.$scope.component.uniqueId &&
1026             this.$scope.component.lifecycleState === 'CERTIFIED' && (this.$scope.component.isService() || this.$scope.component.getComponentSubType() === 'VF')) {
1027             this.ComponentServiceNg2.getDependencies(this.$scope.component.componentType, this.$scope.component.uniqueId).subscribe((response: IDependenciesServerResponse[]) => {
1028                 containsDependencies = response.filter((version) => version.dependencies);
1029                 if (containsDependencies.length > 0) {
1030                     this.$scope.hasNoDependencies = false;
1031                 } else {
1032                     this.$scope.hasNoDependencies = true;
1033                 }
1034             });
1035         }
1036     }
1037 }