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