3bd2255488c8e62a64683d8e55c77e39e53dc2a0
[sdc.git] / catalog-ui / src / app / ng2 / components / layout / top-nav / top-nav.component.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 import * as _ from "lodash";
22 import {Component, Inject, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges} from "@angular/core";
23 import {IHostedApplication, IUserProperties} from "app/models";
24 import {MenuItemGroup, MenuItem} from "app/utils";
25 import {AuthenticationService} from "../../../services/authentication.service";
26 import {SdcConfigToken, ISdcConfig} from "../../../config/sdc-config.config";
27 import {TranslateService} from "../../../shared/translator/translate.service";
28 import {PluginsConfiguration, Plugin} from "app/models";
29 import { Subscription } from "rxjs";
30 // import { Store } from "@ngrx/store";
31 // import { AppState } from "app/ng2/store/app.state";
32 // import * as unsavedChangesReducer from 'app/ng2/store/reducers/unsaved-changes.reducer';
33
34 declare const window:any;
35 @Component({
36     selector: 'top-nav',
37     templateUrl: './top-nav.component.html',
38     styleUrls:['./top-nav.component.less']
39 })
40 export class TopNavComponent implements OnInit, OnChanges {
41     @Input() public version:string;
42     @Input() public menuModel:Array<MenuItemGroup>;
43     @Input() public topLvlSelectedIndex:number;
44     @Input() public hideSearch:boolean;
45     @Input() public searchTerm:string;
46     @Input() public notificationIconCallback:Function;
47     @Input() public unsavedChanges: boolean;
48     @Input() public unsavedChangesCallback: (completeCallback:Function)=> Promise<any>;
49     @Output() public searchTermChange:EventEmitter<string> = new EventEmitter<string>();
50     emitSearchTerm(event:string) {
51         this.searchTermChange.emit(event);
52     }
53
54     private subscription: Subscription;
55     private hasUnsavedChanges: boolean;
56     public topLvlMenu:MenuItemGroup;
57     public user:IUserProperties;
58     private topNavPlugins: Array<Plugin>;
59
60     constructor(private translateService:TranslateService,
61                 @Inject('$state') private $state:ng.ui.IStateService,
62                 private authService:AuthenticationService,
63                 @Inject(SdcConfigToken) private sdcConfig:ISdcConfig) {
64         window.nav = this;
65
66     }
67
68     private _getTopLvlSelectedIndexByState = ():number => {
69         if (!this.topLvlMenu.menuItems) {
70             return 0;
71         }
72
73         let result = -1;
74
75         //set result to current state
76         this.topLvlMenu.menuItems.every((item:MenuItem, index:number)=> {
77             if (item.state === this.$state.current.name) {
78                 if (this.$state.current.name === 'plugins') {
79                     const pluginIdx = _.findIndex(this.topNavPlugins, (plugin: Plugin) => plugin.pluginStateUrl === this.$state.params.path);
80                     if (pluginIdx !== -1) {
81                         result = index + pluginIdx;
82                         return false;
83                     }
84                 } else {
85                     result = index;
86                     return false;
87                 }
88             }
89             return true;
90         });
91
92         //if it's a different state
93         if (result === -1) {
94             //if in 'workspace' -  checking previous state param
95             if (this.$state.includes('workspace')) {
96                 // if previous state is 'dashboard' or 'catalog', then select it - otherwise, use 'catalog' as default for 'workspace'
97                 const selectedStateName = (['dashboard', 'catalog'].indexOf(this.$state.params['previousState']) !== -1)
98                     ? this.$state.params['previousState']
99                     : 'catalog';
100                 result = this.topLvlMenu.menuItems.findIndex((item:MenuItem) => item.state === selectedStateName);
101             }
102
103             //if yet, none is selected, then select the first as default
104             if (result === -1) {
105                 result = 0;
106             }
107         }
108
109         return result;
110     };
111
112     ngOnChanges(changes) {
113         if (changes['menuModel']) {
114             console.log('menuModel was changed!');
115             this.generateMenu();
116         }
117     }
118
119     ngOnInit() {
120         console.log('Nav is init!', this.menuModel);
121         this.user = this.authService.getLoggedinUser();
122         this.topNavPlugins = _.filter(PluginsConfiguration.plugins, (plugin: Plugin) => {
123             return plugin.pluginDisplayOptions["tab"] !== undefined;
124         });
125
126         this.translateService.languageChangedObservable.subscribe((lang) => {
127             let tmpArray: Array<MenuItem> = [
128                 new MenuItem(this.translateService.translate("TOP_MENU_HOME_BUTTON"), null, "dashboard", "goToState", null, null),
129                 new MenuItem(this.translateService.translate("TOP_MENU_CATALOG_BUTTON"), null, "catalog", "goToState", null, null)
130             ];
131
132             // Only designer can perform onboarding
133             if (this.user && this.user.role === 'DESIGNER') {
134                 tmpArray.push(new MenuItem(this.translateService.translate("TOP_MENU_ON_BOARD_BUTTON"), null, "onboardVendor", "goToState", null, null));
135                 _.each(this.sdcConfig.hostedApplications, (hostedApp: IHostedApplication) => {
136                     if (hostedApp.exists) {
137                         tmpArray.push(new MenuItem(hostedApp.navTitle, null, hostedApp.defaultState, "goToState", null, null));
138                     }
139                 });
140             }
141
142             // Adding plugins to top-nav only if they can be displayed for the current connected user role
143             _.each(PluginsConfiguration.plugins, (plugin: Plugin) => {
144                 if (plugin.pluginDisplayOptions["tab"] && (this.user && plugin.pluginDisplayOptions["tab"].displayRoles.includes(this.user.role))) {
145                     tmpArray.push(new MenuItem(plugin.pluginDisplayOptions["tab"].displayName, null, "plugins", "goToState", {path: plugin.pluginStateUrl}, null));
146                 }
147             });
148
149             this.topLvlMenu = new MenuItemGroup(0, tmpArray, true);
150             this.topLvlMenu.selectedIndex = isNaN(this.topLvlSelectedIndex) ? this._getTopLvlSelectedIndexByState() : this.topLvlSelectedIndex;
151             this.generateMenu();
152         });
153     }
154
155     generateMenu() {
156         if (this.menuModel && this.topLvlMenu && this.menuModel[0] !== this.topLvlMenu) {
157             this.menuModel.unshift(this.topLvlMenu);
158         }
159     }
160
161     goToState(state:string, params:any):Promise<boolean> {
162         return new Promise((resolve, reject) => {
163             this.$state.go(state, params || undefined);
164             resolve(true);
165         });
166     }
167
168
169     menuItemClick(itemGroup:MenuItemGroup, item:MenuItem) {
170
171         let onSuccessFunction = () => {
172             this.navigate(itemGroup, item);
173         }
174         if (this.unsavedChanges && this.unsavedChangesCallback){
175             this.unsavedChangesCallback(onSuccessFunction).then((onSuccess)=> {
176                 this.navigate(itemGroup, item);
177             }, (onReject) => {});
178         } else {
179             this.navigate(itemGroup, item);
180         }
181     }
182
183     navigate(itemGroup:MenuItemGroup, item:MenuItem) {
184         itemGroup.itemClick = false;
185         let onSuccess = ():void => {
186             itemGroup.selectedIndex = itemGroup.menuItems.indexOf(item);
187         };
188         let onFailed = ():void => {
189         };
190
191         if (item.callback) {
192             (item.callback.apply(undefined, item.params)).then(onSuccess, onFailed);
193         } else {
194             this[item.action](item.state, item.params).then(onSuccess, onFailed);
195         }
196     }
197
198 }