diff options
Diffstat (limited to 'catalog-ui/src/app/ng2/components/layout/top-nav')
3 files changed, 427 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html new file mode 100644 index 0000000000..55c4bf0460 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html @@ -0,0 +1,53 @@ +<nav class="top-nav"> + + <div class="asdc-app-title-wrapper"> + <a class="asdc-app-title">{{ 'PROJECT_TITLE'|translate }}</a> + <div class="asdc-version"> v.{{version}}</div> + </div> + + <ul class="top-menu" *ngIf="!menuModel && topLvlMenu"> + <!-- no hierarchy & dropdowns mode --> + <li *ngFor="let item of topLvlMenu.menuItems; let i = index" + [ngClass]="{'selected': i == topLvlMenu.selectedIndex}"> + <a (click)="menuItemClick(topLvlMenu, item)" + [attr.data-tests-id]="'main-menu-button-' + item.text.toLowerCase()">{{item.text}}</a> + </li> + </ul> + + <ul class="top-menu" *ngIf="menuModel"> + <!-- with hierarchy & dropdowns mode --> + <ng-container *ngFor="let groupItem of menuModel; let $index = index; let $last = last"> + <li [ngClass]="{'selected': $last }"> + <a (click)="menuItemClick(groupItem, groupItem.menuItems[groupItem.selectedIndex])" + [attr.data-tests-id]="'breadcrumbs-button-' + $index"> + {{groupItem.menuItems[groupItem.selectedIndex].text}} + </a> + </li> + <li class="triangle-dropdown" + [ngClass]="{'item-click': groupItem.itemClick}" (mouseover)="groupItem.itemClick = true"> + <div class="triangle"><span class="sprite-new arrow-right"></span></div> + <ul class="sub-menu"> + <li *ngFor="let ddItem of groupItem.menuItems; let $index2 = index" + (click)="menuItemClick(groupItem, ddItem)" + [ngClass]="{'selected': $index2 == groupItem.selectedIndex, 'disabled': ddItem.isDisabled}" + [attr.data-tests-id]="'sub-menu-button-' + ddItem.text.toLowerCase()"> + <span sdc-smart-tooltip="">{{ddItem.text}}</span> + </li> + </ul> + </li> + </ng-container> + </ul> + + <div class="top-search" [hidden]="hideSearch === true"> + <input type="text" + class="search-text" + placeholder="Search" + [ngModel]="searchTerm" + (ngModelChange)="emitSearchTerm($event)" + data-tests-id="main-menu-input-search" /> + <span class="w-sdc-search-icon magnification"></span> + </div> + + <div class="notification-icon" [ngClass]="{'disabled' : progress > 0}" *ngIf="user.role === 'DESIGNER' && notificationIconCallback" (click)="notificationIconCallback()" tooltip="Vendor Software Product Repository" tooltipPlacement="left" data-tests-id="repository-icon"></div> + +</nav> diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.less b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.less new file mode 100644 index 0000000000..dc666cbf00 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.less @@ -0,0 +1,225 @@ +@import "../../../../../assets/styles/variables"; +@import "../../../../../assets/styles/variables-old"; +@import "../../../../../assets/styles/mixins_old"; +@import "../../../../../assets/styles/sprite"; + +.top-nav { + position: fixed; + top: @header_height; + background-color: @main_color_p; + .box-shadow(0px 1px 3px 0px rgba(0, 0, 0, 0.33)); + width: 100%; + height: @top_nav_height; + line-height: @top_nav_height; + z-index: 10; + display: flex; + flex-direction: row; + align-items: center; + + .asdc-app-title-wrapper { + flex-grow: 1; + line-height: 16px; + margin: 0 20px; + + a.asdc-app-title { + //.m_18_r; + text-decoration: none; + } + + .asdc-version { + //.m_12_r; + .opacity(0.8); + line-height: 14px; + flex-grow: 1; + } + + } + + ul.top-menu { + list-style-type: none; + margin: 0 0 0 20px; + padding: 0; + flex-grow: 999; + + & > li { + float: left; + cursor: pointer; + line-height: 50px; + height: 50px; + padding: 0 20px; + + &.selected { + border-bottom: solid 4px @main_color_a; + + a { + color: @func_color_s; + } + } + + /*&:hover { + border-bottom: solid 4px @main_color_a; + }*/ + + a { + font-family: @font-opensans-medium; + color: @main_color_m; + font-size: 16px; + display: block; + text-align: center; + text-decoration: none; + } + + &.triangle-dropdown { + padding: 0; + position: relative; + + div.triangle { + margin-top: 15px; + border-radius: 2px; + width: 17px; + height: 18px; + + //temp use - until new triangle gets in + line-height: 18px; + text-align: center; + font-size: 10px; + + &:hover { + background-color: rgba(156, 156, 156, 0.2); + + span { + .arrow-right-hover; + } + } + } + + + li a { + font-size: 16px; + } + + ul.sub-menu { + .perfect-scrollbar; + position: absolute; + left: 0; + top: 40px; + z-index: 1; + + overflow-x: hidden; + overflow-y: auto; + max-height: 0; + -webkit-transition: max-height 200ms ease-in; + -moz-transition: max-height 200ms ease-in; + -o-transition: max-height 200ms ease-in; + transition: max-height 200ms ease-in; + + padding: 0; + background-color: white; + visibility: hidden; + + li { + + height: 35px; + background-color: white; + font-size: 13px; + width: 150px; + line-height: 35px; + padding: 0 10px; + + &.disabled { + opacity: 1; + } + &.selected { + background-color: @tlv_color_v; + font-weight: bold; + } + &:hover { + color: @main_color_a; + } + span { + height: 35px; + width: 130px; + display: inline; + white-space: nowrap; + overflow: hidden; + } + } + } + &.item-click:hover ul.sub-menu, + &.item-click:active ul.sub-menu { + visibility: visible; + max-height: 500px; + border: 1px solid @func_color_b; + border-radius: 2px; + box-shadow: 0px 2px 2px 0px rgba(24, 24, 25, 0.1); + + div ul { + + } + } + } + } + + } + + .top-search { + position: relative; + flex-grow: 1; + padding: 0 20px; + + input.search-text { + .border-radius(2px); + width: 245px; + height: 32px; + line-height: 32px; + border: 1px solid @main_color_o; + outline: none; + text-indent: 10px; + + &::-webkit-input-placeholder { font-style: italic; } /* Safari, Chrome and Opera */ + &:-moz-placeholder { font-style: italic; } /* Firefox 18- */ + &::-moz-placeholder { font-style: italic; } /* Firefox 19+ */ + &:-ms-input-placeholder { font-style: italic; } /* IE 10+ */ + &:-ms-input-placeholder { font-style: italic; } /* Edge */ + /* font-style: italic; + }*/ + /* Firefox 18- */ + &::-moz-placeholder { + font-style: italic; + } + /* Firefox 19+ */ + &:-ms-input-placeholder { + font-style: italic; + } + /* IE 10+ */ + &:-ms-input-placeholder { + font-style: italic; + } + /* Edge */ + } + + .magnification { + position: absolute; + top: 19px; + right: 26px; + } + + } + + .notification-icon { + cursor: pointer; + flex-grow: 1; + margin: 0 10px 6px 0; + .sprite-new; + .vsp-list-icon; + + &:hover { + .vsp-list-icon-hover; + } + + &:active { + .vsp-list-icon-active; + } + + } + +} diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts new file mode 100644 index 0000000000..f48aa4801f --- /dev/null +++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {Component, Inject, Input, Output, EventEmitter} from "@angular/core"; +import {IHostedApplication, IUserProperties} from "app/models"; +import {MenuItemGroup, MenuItem} from "app/utils"; +import {UserService} from "../../../services/user.service"; +import {SdcConfigToken, ISdcConfig} from "../../../config/sdc-config.config"; +import {TranslateService} from "../../../shared/translator/translate.service"; + + +declare const window:any; +@Component({ + selector: 'top-nav', + templateUrl: './top-nav.component.html', + styleUrls:['./top-nav.component.less'] +}) +export class TopNavComponent { + @Input() public version:string; + @Input() public menuModel:Array<MenuItemGroup>; + @Input() public topLvlSelectedIndex:number; + @Input() public hideSearch:boolean; + @Input() public searchTerm:string; + @Input() public notificationIconCallback:Function; + @Output() public searchTermChange:EventEmitter<string> = new EventEmitter<string>(); + emitSearchTerm(event:string) { + this.searchTermChange.emit(event); + } + + public topLvlMenu:MenuItemGroup; + public user:IUserProperties; + + constructor(private translateService:TranslateService, + @Inject('$state') private $state:ng.ui.IStateService, + private userService:UserService, + @Inject(SdcConfigToken) private sdcConfig:ISdcConfig) { + window.nav = this; + } + + private _getTopLvlSelectedIndexByState = ():number => { + if (!this.topLvlMenu.menuItems) { + return 0; + } + + let result = -1; + + //set result to current state + this.topLvlMenu.menuItems.forEach((item:MenuItem, index:number)=> { + if (item.state === this.$state.current.name) { + result = index; + } + }); + + //if it's a different state , checking previous state param + if (result === -1) { + this.topLvlMenu.menuItems.forEach((item:MenuItem, index:number)=> { + if (item.state === this.$state.params['previousState']) { + result = index; + } + }); + } + + if (result === -1) { + result = 0; + } + + return result; + }; + + ngOnChanges(changes) { + if (changes['menuModel']) { + console.log('menuModel was changed!'); + this.generateMenu(); + } + } + + ngOnInit() { + console.log('Nav is init!', this.menuModel); + this.user = this.userService.getLoggedinUser(); + + this.translateService.languageChangedObservable.subscribe((lang) => { + let tmpArray: Array<MenuItem> = [ + new MenuItem(this.translateService.translate("TOP_MENU_HOME_BUTTON"), null, "dashboard", "goToState", null, null), + new MenuItem(this.translateService.translate("TOP_MENU_CATALOG_BUTTON"), null, "catalog", "goToState", null, null) + ]; + + // Only designer can perform onboarding + if (this.user && this.user.role === 'DESIGNER') { + tmpArray.push(new MenuItem(this.translateService.translate("TOP_MENU_ON_BOARD_BUTTON"), null, "onboardVendor", "goToState", null, null)); + _.each(this.sdcConfig.hostedApplications, (hostedApp: IHostedApplication) => { + if (hostedApp.exists) { + tmpArray.push(new MenuItem(hostedApp.navTitle, null, hostedApp.defaultState, "goToState", null, null)); + } + }); + } + + this.topLvlMenu = new MenuItemGroup(0, tmpArray, true); + this.topLvlMenu.selectedIndex = isNaN(this.topLvlSelectedIndex) ? this._getTopLvlSelectedIndexByState() : this.topLvlSelectedIndex; + + this.generateMenu(); + }); + } + + generateMenu() { + if (this.menuModel && this.topLvlMenu && this.menuModel[0] !== this.topLvlMenu) { + this.menuModel.unshift(this.topLvlMenu); + } + } + + goToState(state:string, params:Array<any>):Promise<boolean> { + return new Promise((resolve, reject) => { + this.$state.go(state, params && params.length > 0 ? [0] : undefined); + resolve(true); + }); + } + + menuItemClick(itemGroup:MenuItemGroup, item:MenuItem) { + itemGroup.itemClick = false; + + let onSuccess = ():void => { + itemGroup.selectedIndex = itemGroup.menuItems.indexOf(item); + }; + let onFailed = ():void => { + }; + + if (item.callback) { + (item.callback.apply(undefined, item.params)).then(onSuccess, onFailed); + } else { + this[item.action](item.state, item.params).then(onSuccess, onFailed); + } + } +} |