diff options
author | Sunder Tattavarada <statta@research.att.com> | 2020-01-28 22:58:33 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2020-01-28 22:58:33 +0000 |
commit | 602630618626d0ca1fd5fe6ac4f3347029bfd4c7 (patch) | |
tree | 41746329526c99771015c16e2da2edb17cabbd5e /portal-FE-common/src/app/pages/functional-menu | |
parent | a5aa8126eeaf5a2f84df510f3208eafed483ab52 (diff) | |
parent | 91e3434fc7c515416ff2da10d55acf1d2dbcde71 (diff) |
Merge "Adding new components with portal-FE-common"
Diffstat (limited to 'portal-FE-common/src/app/pages/functional-menu')
9 files changed, 1231 insertions, 0 deletions
diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.html b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.html new file mode 100644 index 00000000..5e10b78f --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.html @@ -0,0 +1,100 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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============================================ + + +--> + +<div class="container"> + <div class="functionalMenu-details-modal"> + <!--Modal Headers--> + <div class="modal-header"> + <h4 class="modal-title">Functional Menu</h4> + <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross')"> + <span aria-hidden="true">×</span> + </button> + </div> + + <!--Modal Body goes here--> + <div class="modal-body"> + <div class="parent"> + <div class="item-label">Parent</div> + <input id="input-parent" class="functionalMenu-height" + [(ngModel)]="nodedetails.menuLocation" [disabled]="isParentDisable" + type="text" name="parent" readonly="readonly" /> + </div> + <div class="title" > + <div class="item-label">Title</div> + <input id="input-title" placeholder="Enter text" class="functionalMenu-height" + [(ngModel)]="nodedetails.name" type="text" autocomplete="off" name="title" maxlength="100" [disabled]="isViewMode"/> + </div> + <div class="url" > + <div class="item-label">URL</div> + <input id="input-title" placeholder="http://" class="functionalMenu-height" + [(ngModel)]="nodedetails.url" type="text" autocomplete="off" name="url" maxlength="100" [disabled]="isViewMode"/> + </div> + <div class="application-select"> + <mat-form-field> + <mat-label>App</mat-label> + <mat-select name="functional-menu-application-select" [disabled]="isViewMode" + [(ngModel)]="nodedetails.selectedAppIndex" + (ngModelChange)="updateSelectedApp(nodedetails.selectedAppIndex)" + [(value)]="selectedApp" + > + <mat-option *ngFor="let d of availableApps" [value]="d.index" >{{d.title}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div class="role-select" [hidden]="hideRoleField"> + <mat-form-field> + <mat-label>Role</mat-label> + <mat-select name="functional-menu-role-select" [disabled]="isViewMode" + [(ngModel)]="nodedetails.selectedRole" [(value)]="selectedRole" + > + <mat-option *ngFor="let d of availableRoles" [value]="d.roleId" >{{d.rolename}}</mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + + <!--Modal Footer goes Here--> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" (click)="switchToAddMode()">Add</button> + <button type="button" class="btn btn-primary" (click)="switchToEditMode()">Edit</button> + <button type="button" class="btn btn-primary" *ngIf="(isEditMode)" (click)="saveChanges()">Save</button> + <button type="button" class="btn btn-primary" (click)="deleteMenuItem()">Delete</button> + <button type="button" class="btn btn-primary" (click)="activeModal.close('Close')">Cancel</button> + </div> + </div> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.scss b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.scss new file mode 100644 index 00000000..ba9a1e37 --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.scss @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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============================================ + * + * + */ + +::ng-deep .modal-dialog { + max-width: 550px; + width: 550px; + overflow-x: auto; + overflow-y: auto; +} + +::ng-deep .mat-form-field-infix { + display: block; + position: relative; + flex: auto; + min-width: 0; + width: 448px !important; +} + +.container .functionalMenu-details-modal { + padding: 16px; + height: 537px; + overflow: auto; +} + +.functionalMenu-details-modal input[type="text"] { + width: 28em; + margin-bottom: 10px; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.spec.ts b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.spec.ts new file mode 100644 index 00000000..de79b9d8 --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.spec.ts @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FunctionalMenuDialogComponent } from './functional-menu-dialog.component'; + +describe('FunctionalMenuDialogComponent', () => { + let component: FunctionalMenuDialogComponent; + let fixture: ComponentFixture<FunctionalMenuDialogComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FunctionalMenuDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FunctionalMenuDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.ts b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.ts new file mode 100644 index 00000000..a1839732 --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu-dialog/functional-menu-dialog.component.ts @@ -0,0 +1,446 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { FunctionalMenuService } from 'src/app/shared/services'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; + +@Component({ + selector: 'app-functional-menu-dialog', + templateUrl: './functional-menu-dialog.component.html', + styleUrls: ['./functional-menu-dialog.component.scss'] +}) +export class FunctionalMenuDialogComponent implements OnInit { + + @Input() nodedata: any; + @Input() operationName: string; + @Output() passEntry: EventEmitter<any> = new EventEmitter(); + isEditMode: boolean = false; + isViewMode: boolean = false; + isAddItemMode: boolean = false; + selectedItem: any; + result: any; + availableRoles: any; + preSelectedRoles: any; + isAllApplications: boolean = false; + availableApps: any + selectedRole: any = []; + selectedApp={ + index:null, + isDisabled: null + }; + selectedAppIndex: any; + menutitle:string; + menuLocation:string; + nodedetails: any; + isParentDisable:boolean =true; + hideRoleField:boolean = true; + conflictMessages = {}; + functionalMenuForm = {}; + + constructor(public functionalMenuService : FunctionalMenuService, public ngbModal: NgbModal, public activeModal: NgbActiveModal) { } + + ngOnInit() { + //console.log("nodedata in dialog ",this.nodedata); + this.nodedetails = Object.assign({}, this.nodedata); + this.isViewMode = true; + this.selectedItem = this.nodedata; + this.selectedRole = []; + this.availableRoles = []; + if(this.nodedata && (this.isViewMode || this.isEditMode) && this.isLeafMenuItem(this.nodedetails)){ + this.selectedApp.index = this.nodedetails.appid; + this.selectedAppIndex=this.nodedetails.appid; + this.getAvailableRoles(this.selectedAppIndex); + } + + if(this.isViewMode || this.isEditMode){ + this.nodedetails.menutitle = this.nodedetails.name; + this.nodedetails.menuLocation = this.isParentMenuItem(this.nodedata) ? this.nodedata.name : this.nodedata.parent.name; + }else{ + this.nodedetails.menutitle = ''; + this.nodedetails.menuLocation = this.nodedata.name; + } + this.nodedetails.selectedAppIndex = (this.selectedItem.appid) ? this.selectedItem.appid : 0; + this.getAvailableApps(); + if(this.selectedItem.appid && this.selectedItem.appid >0){ + this.getAvailableRoles(this.selectedItem.appid); + } + } + + switchToEditMode(){ + //console.log("switchToEditMode :: ",this.nodedata); + this.isViewMode = false; + this.isEditMode = true; + this.isParentDisable =true; + this.nodedetails.name = this.selectedItem.name; + this.nodedetails.url = this.selectedItem.url; + this.nodedetails.selectedAppIndex = (this.selectedItem.appid) ? this.selectedItem.appid : 0; + this.nodedetails.selectedRole = (this.selectedItem.roles) ? this.selectedItem.roles : 0; + } + + switchToAddMode(){ + //console.log("switchToAddMode :: ",this.nodedata); + if(this.selectedItem != null && this.selectedItem.getLevel() >= 4){ + this.openConfirmationModal("","You are not allowed to have a menu item at a level greater than 4."); + return ; + } + //this.isViewMode = false; + this.isViewMode = false; + this.isEditMode = true; + this.isAddItemMode = true; + this.nodedetails.name = ""; + this.nodedetails.url = ""; + this.nodedetails.selectedAppIndex = 0; + this.nodedetails.selectedRole = 0; + } + + /** + * deleteMenuItem + * @param selectedItem + */ + deleteMenuItem(){ + if(this.selectedItem.children!=null && this.selectedItem.children.length>0){ + const modalRef = this.ngbModal.open(ConfirmationModalComponent); + modalRef.componentInstance.title = ""; + modalRef.componentInstance.message = 'You are not allowed to delete a menu item that has children. You can only delete leaf menu items.'; + modalRef.result.then((result) => { }, (resut) => {return;}); + }else{ + const modalRef = this.ngbModal.open(InformationModalComponent); + modalRef.componentInstance.title = "Confirmation"; + modalRef.componentInstance.message = 'Are you sure you want to delete '+ this.selectedItem.name+' ?'; + modalRef.result.then((result) => { + if (result === 'Ok') { + this.functionalMenuService.deleteMenuItem(this.selectedItem.menuId) + .subscribe(_data => { + this.result = _data + this.passEntry.emit(this.result); + let successMsg = "Item Deleted Successfully"; + this.openConfirmationModal("Success",successMsg); + this.ngbModal.dismissAll(); + }, error =>{ + console.log(error); + let deleteErrorMsg = 'There was an error while deleting the item.'+error.message; + this.openConfirmationModal("Error",deleteErrorMsg); + return; + }); + } + }, (resut) => { + + }) + } + } + + updateSelectedApp(appid){ + //console.log("updateSelectedApp called with appId :: ",appid); + if (!appid) { + return; + } + this.getAvailableRoles(appid); + } + + getAvailableRoles(appid){ + //console.log("getAvailableRoles called with appId :: ",appid); + if (appid != null && appid >0) { + this.functionalMenuService.getManagedRolesMenu(appid) + .subscribe(rolesObj => { + this.availableRoles = rolesObj; + if(this.availableRoles && this.availableRoles.length >0){ + this.hideRoleField = false; + } + this.preSelectedRoles = {roles:[]}; + this.preSelectedRoles = {roles:[]}; + + if((this.isEditMode) && this.isMidLevelMenuItem(this.nodedata)){ + // in Edit flow , for Midlevel menu item no need to preSelect. + this.preSelectedRoles = {roles:[]}; + }else if(this.nodedata && this.isEditMode && this.isLeafMenuItem(this.nodedata) && this.nodedata.appid!=appid) { + // in Edit flow , for LeafMenuItem, if appid changed then no need to preSelect. + this.preSelectedRoles = {roles:[]}; + }else{ + if(this.nodedata && this.nodedata.roles){ + for(var i=0; i< this.nodedata.roles.length; i++){ + var role = {"roleId": this.nodedata.roles[i]}; + this.preSelectedRoles.roles.push(role); + } + } + } + + if(this.nodedata.rolesObj){ + for(var i=0; i< this.nodedata.rolesObj.length;i++){ + //this.availableRoles[i].isApplied = false; + for(var j=0;j<this.preSelectedRoles.roles.length;j++){ + if(this.preSelectedRoles.roles[j].roleId==this.availableRoles[i].roleId){ + this.availableRoles[i].isApplied=true; + this.nodedetails.selectedRole = (this.preSelectedRoles.roles[j]) ? this.preSelectedRoles.roles[j] : 0; + break; + } + } + } + } + }, error =>{ + console.log(error); + let errorMsg = 'There was an error while gettting available roles. ' + error.message; + this.openConfirmationModal("",errorMsg); + return; + }); + //console.log("this.availableRoles >>>>>",this.availableRoles); + }else{ + console.log("FunctionalMenuDialogComponent::getAvailableRoles: appid was null or -1"); + } + } + + getAvailableApps(){ + this.isAllApplications = true; + this.functionalMenuService.getAvailableApplications() + .subscribe(apps => { + this.availableApps = apps; + if (this.nodedetails && this.nodedetails.index) { + for (var i = 0; i < this.availableApps.length; i++) { + if (apps[i].index === this.nodedetails.index) { + //console.log("MenuDetailsModalCtrl::getAvailableApps: found app with index: " + this.nodedetails.index); + //console.log("MenuDetailsModalCtrl::getAvailableApps: setting isDisabled to: " + !apps[i].enabled); + this.nodedetails.isDisabled = !apps[i].enabled; + break; + } + } + //console.log("didn't find index: " + this.nodedetails.index); + } + }, error =>{ + console.log(error); + this.isAllApplications = false; + let errorMsg = 'There was a problem retrieving the Applications. '+error.message; + this.openConfirmationModal("Error",errorMsg); + }); + } + + isLeafMenuItem(menu: any){ + return menu.children.length>0 ? false : true; + } + + isMidLevelMenuItem(menu: any){ + return menu.parentMenuId!=null && menu.children.length>0 ? true : false; + } + + isParentMenuItem(menu: any){ + return menu.parentMenuId!=null ? false : true; + }; + + isRoleSelected(){ + var selectedRoleIds=[]; + for(var i=0;i<this.availableRoles.length;i++){ + if(this.availableRoles[i].isApplied){ + selectedRoleIds.push(this.availableRoles[i].roleId); + return true; + } + } + return false; + } + + getDialogTitle = (source) => { + switch (source) { + case 'edit': + return "Functional Menu - Edit"; + case 'view': + return "Functional Menu - View"; + case 'add': + return "Functional Menu - Add"; + default: + return "Functional Menu"; + }; + } + + saveChanges(){ + if(!this.nodedetails.menuLocation || !this.nodedetails.name + || !this.nodedetails.url || !this.nodedetails.selectedAppIndex + || !this.nodedetails.selectedAppIndex || !this.nodedetails.selectedRole){ + this.openConfirmationModal("","All fields are mandatory, please provide inputs for all the fields."); + return; + } + /* + if(!!this.nodedetails.url && (!this.selectedApp || this.selectedAppIndex <=0)) { + this.openConfirmationModal("","Please select the appropriate app, or remove the url"); + return; + }else if(!this.nodedetails.url && (this.selectedApp) && this.selectedApp.index>0){ + this.openConfirmationModal("","Please enter url, or select No Application"); + return; + }else if(!this.nodedetails.menutitle){ + this.openConfirmationModal("","Please enter the Menu title"); + return; + } + */ + + if(this.isAddItemMode){ + if(this.selectedItem != null && this.selectedItem.getLevel() >= 4){ + this.openConfirmationModal("","You are not allowed to have a menu item at a level greater than 4."); + return ; + }else{ + let data = null; + let selectedMenuDetails = null; + this.functionalMenuService.getFunctionalMenu(this.selectedItem.menuId) + .subscribe(_data => { + selectedMenuDetails = _data + if((this.selectedItem.children===null || this.selectedItem.children.length == 0) && (!!selectedMenuDetails.url + || !!selectedMenuDetails.appid || !!selectedMenuDetails.roles)){ + let warning_message = 'Warning: the child menu item "' + + this.selectedItem.name + '" is already configured with an application. You can create a new mid-level menu item.'; + this.openConfirmationModal("",warning_message); + return; + }else{ + if(this.selectedItem){ + var selectedRoleIds=[]; + //console.log("Selected Role ID ; ",this.nodedetails.selectedRole); + if(this.nodedetails.selectedRole){ + selectedRoleIds.push(this.nodedetails.selectedRole); + } + + let applicationid: any = null; + if(!this.nodedata){ + applicationid = null; + }else{ + applicationid = this.nodedata.appid; + } + var newMenuItem = { + menuId:null, // this is a new menu item + column:this.nodedata.column, + text:this.nodedetails.name, + // We are creating this new menu item under the menu item that was clicked on. + parentMenuId:this.nodedata.menuId, + url:(this.nodedetails.url) ? this.nodedetails.url : null, + appid:(this.nodedetails.selectedAppIndex) ? this.nodedetails.selectedAppIndex: null, + roles:selectedRoleIds + }; + //console.log("Add menu Item newMenuItem :: ",newMenuItem) + this.functionalMenuService.saveMenuItem(newMenuItem) + .subscribe(_data => { + this.result = _data + //console.log("add menu item response :: ",_data); + this.passEntry.emit(this.result); + let successMsg = "Item added successfully"; + this.openConfirmationModal("Success",successMsg); + }, error =>{ + console.log(error); + if(error.status === 409){//Conflict + this.handleConflictErrors(error); + } else { + let errorMsg = "There was a problem saving your menu. Please try again later. Error Status: "+error.status + this.openConfirmationModal("",errorMsg); + return; + } + }); + } + } + }, error =>{ + //console.log(error); + let errorMsg = "There was a problem saving your menu. Please try again later. Error Status: "+error.status + this.openConfirmationModal("",errorMsg ); + return; + }); + } + }else{ + //edit mode.. + //console.log('MenuDetailsModalCtrl::saveChanges: Will be saving an edit menu item'); + var selectedRoleIds=[]; + //console.log("Selected Role ID ---->>>> ",this.nodedetails.selectedRole); + if(this.nodedetails.selectedRole){ + selectedRoleIds.push(this.nodedetails.selectedRole); + } + let activeMenuItem = { + menuId:this.nodedata.menuId, + column:this.nodedata.column, + text:this.nodedetails.name, + parentMenuId:this.nodedata.parentMenuId, + url:(this.nodedetails.url) ? this.nodedetails.url : null, + appid: (this.nodedetails.selectedAppIndex) ? this.nodedetails.selectedAppIndex: null, + roles:selectedRoleIds + }; + if ((activeMenuItem.appid==null && activeMenuItem.url=="") || (activeMenuItem.appid==null && activeMenuItem.url=="undefined")) { + activeMenuItem.roles = null; + } + //console.log("Update menu Item activeMenuItem :: ",activeMenuItem); + this.functionalMenuService.saveEditedMenuItem(activeMenuItem) + .subscribe(_data => { + this.result = _data + //console.log("Edit menu item response :: ",_data); + this.passEntry.emit(this.result); + let successMsg = "Item updated successfully"; + this.openConfirmationModal("Success",successMsg); + //this.ngbModal.dismissAll(); + }, error =>{ + //console.log(error); + let errorMsg = "There was a problem updating your menu. Please try again later. Error Status: "+error.status; + this.openConfirmationModal("",errorMsg); + return; + }); + } + } + + //This part handles conflict errors (409) + handleConflictErrors(error){ + if(!error.data){ + return; + } + if(!error.data.length){ //support objects + error.data = [error.data] + } + //console.log('MenuDetailsModalCtrl::handleConflictErrors: err.data = ' + JSON.stringify(error.data)); + if(error.data){ + error.data.forEach(item => { + //set conflict message + this.conflictMessages[item.field.name] = item.errorCode; + //set field as invalid + //console.log('MenuDetailsModalCtrl::handleConflictErrors: fieldName = ' + item.field.name); + this.functionalMenuForm[item.field.name].$setValidity('conflict', false); + }); + } + } + + openConfirmationModal(_title: string, _message: string) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = _title; + modalInfoRef.componentInstance.message = _message; + } + + openInformationModal(_title: string, _message: string){ + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = _title; + modalInfoRef.componentInstance.message = _message; + return modalInfoRef; + } +} diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.html b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.html new file mode 100644 index 00000000..d898563b --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.html @@ -0,0 +1,52 @@ +<!-- + ============LICENSE_START========================================== + ONAP Portal + =================================================================== + Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + =================================================================== + + Unless otherwise specified, all software contained herein is licensed + under the Apache License, Version 2.0 (the "License"); + you may not use this software 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. + + Unless otherwise specified, all documentation contained herein is licensed + under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + you may not use this documentation except in compliance with the License. + You may obtain a copy of the License at + + https://creativecommons.org/licenses/by/4.0/ + + Unless required by applicable law or agreed to in writing, documentation + 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============================================ + + --> + +<div class="container"> + <div id="title" class="w-onap-main-view-title"> + <h1 class="heading-page">Edit Functional Menu</h1> + </div> + <div id="jqTree"></div> + <div class="functional-admin-button-container"> + <button id="regenrate-functionalmenu-btn" + class="btn btn-alt btn-small" + (click)="regenerateFunctionalMenuAncestors()">Regenerate Menu + </button> + <div class="regenerate-functionalmenu-btn-txt"> + <span class="n16r">Click when you are done with your changes.</span> + </div> + </div> +</div> diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.scss b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.scss new file mode 100644 index 00000000..c716252e --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.scss @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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============================================ + * + * + */ + +.functional-menu-main { + background-color: #fff; + position: fixed; + top: 105px; + left: 0; + right: 0; + bottom: 75px; + padding-top: 10px; + overflow-y: scroll; + padding-left: 0; +} + +.functional-menu-main .functional-menu-container { + position: relative; + padding-right: 0; + padding-left: 0; + padding-bottom: 32px; + background-color: #fff; +} + +.w-ecomp-main-view-title { + color: #191919; + font-family: Omnes-ECOMP-W02-Medium,Arial; + font-size: 24px; + width: 1170px; + padding-bottom: 15px; + margin: auto; +} + +.functional-menu-main .functional-menu-container .tree { + margin: auto; + width: 1170px; + font-size: 16px; +} + +.functional-admin-button-container { + padding-top: 10px; + width: 1170px; + margin: auto; +} + +.btn-small { + padding: 10px 19px 9px 18px; + font-size: 1.5rem; + border-radius: 8px; +} + +.btn-alt { + border-color: #087ac2 transparent #0568ae; + background-color: #0568ae; + background: linear-gradient(to bottom, #087ac2 0%, #0568ae 100%); + color: #ffffff; +} + +.functional-menu-main .regenerate-functionalmenu-btn-txt { + color: #000; +} diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.spec.ts b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.spec.ts new file mode 100644 index 00000000..c5c562ed --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FunctionalMenuComponent } from './functional-menu.component'; + +describe('FunctionalMenuComponent', () => { + let component: FunctionalMenuComponent; + let fixture: ComponentFixture<FunctionalMenuComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FunctionalMenuComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FunctionalMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.ts b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.ts new file mode 100644 index 00000000..655b4cb4 --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/functional-menu.component.ts @@ -0,0 +1,192 @@ +/*- + * ============LICENSE_START========================================== + * ONAP Portal + * =================================================================== + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * =================================================================== + * + * Unless otherwise specified, all software contained herein is licensed + * under the Apache License, Version 2.0 (the "License"); + * you may not use this software 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. + * + * Unless otherwise specified, all documentation contained herein is licensed + * under the Creative Commons License, Attribution 4.0 Intl. (the "License"); + * you may not use this documentation except in compliance with the License. + * You may obtain a copy of the License at + * + * https://creativecommons.org/licenses/by/4.0/ + * + * Unless required by applicable law or agreed to in writing, documentation + * 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, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { FunctionalMenuService } from 'src/app/shared/services'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { FunctionalMenuDialogComponent } from './functional-menu-dialog/functional-menu-dialog.component'; + + +@Component({ + selector: 'app-functional-menu', + templateUrl: './functional-menu.component.html', + styleUrls: ['./functional-menu.component.scss'] +}) +export class FunctionalMenuComponent implements OnInit { + + result: any; + functionalMenu: any = []; + treedata = []; + isEditMode: boolean; + operationName: string; + self: any; + constructor(public functionalMenuService : FunctionalMenuService, public ngbModal: NgbModal) { } + + ngOnInit() { + this.self = this; + this.functionalMenu = []; + this.getFunctionalMenu(); + + } + + /** + * regenerateFunctionalMenuAncestors + */ + regenerateFunctionalMenuAncestors(){ + this.functionalMenuService.regenerateFunctionalMenuAncestors() + .subscribe(_data => { + this.result = _data + if(this.result){ + const modalRef = this.ngbModal.open(ConfirmationModalComponent); + modalRef.componentInstance.title = ""; + modalRef.componentInstance.message = 'You have successfully regenerated the menu.'; + modalRef.result.then((result) => { }, (resut) => {return;}); + this.getFunctionalMenu(); + } + }, error =>{ + console.log(error); + const modalRef = this.ngbModal.open(ConfirmationModalComponent); + modalRef.componentInstance.title = ""; + modalRef.componentInstance.message = 'There was an error while regenerating the menu.'; + modalRef.result.then((result) => { }, (resut) => {return;}); + }); + } + + /** + * getFunctionalMenu + */ + getFunctionalMenu(){ + let actualData=[]; + this.functionalMenuService.getManagedFunctionalMenu() + .subscribe(_data => { + this.result = _data; + if(this.result){ + for(let i = 0; i < this.result.length; i++){ + this.result[i].children=[]; + this.result[i].label= this.result[i].text; + this.result[i].id= this.result[i].text; + } + //Adding actual child items to children array in res objects + for(let i = 0; i < this.result.length; i++){ + let parentId=this.result[i].menuId; + for(let j = 0; j < this.result.length; j++){ + let childId=this.result[j].parentMenuId; + if(parentId===childId){ + this.result[i].children.push(this.result[j]); + } + } + } + // Sort the top-level menu items in order based on the column + this.result.sort(function(a, b) { + return a.column-b.column; + }); + + // Sort all the children in order based on the column + for(let i = 0; i < this.result.length; i++){ + this.result[i].children.sort(function(a, b){ + return a.column-b.column; + }); + } + + //Forming actual parent items + for(let i = 0; i < this.result.length; i++){ + let parentId= this.result[i].parentMenuId; + if(parentId===null){ + actualData.push( this.result[i]); + } + } + + this.treedata = actualData; + //console.log("this.treedata :: ",this.treedata); + + if(this.treedata){ + this.buildTree(this.treedata,this.ngbModal, this.self); + } + + } + }, error =>{ + console.log(error); + }); + + } + + /** + * buildTree + * @param treedataarray + * @param ngbModal + */ + buildTree(treedataarray,ngbModal: NgbModal , _self){ + //console.log("treedataarray>>>>",treedataarray); + $(function() { + $('#jqTree').tree('loadData', treedataarray); + $('#jqTree').tree({ + data: treedataarray, + autoOpen: false, + dragAndDrop: true, + onCreateLi: function(node, $li) { + ////console.log("node >>",node); + } + }).on( + 'tree.contextmenu', + function(event:any) { + // The clicked node is 'event.node' + var node = event.node; + openMenuDetailsModal(node, "view"); + } + ); + + var openMenuDetailsModal = function(node: any, actionName: string ){ + const modalRef = ngbModal.open(FunctionalMenuDialogComponent, { size: 'lg' }); + modalRef.componentInstance.title = 'Functional Menu ',actionName; + if(node != 'undefined' && node){ + modalRef.componentInstance.nodedata = node; + modalRef.componentInstance.operationName = actionName; + }else{ + modalRef.componentInstance.nodedata = {}; + } + modalRef.componentInstance.passEntry.subscribe((receivedEntry: any) => { + //console.log("receivedEntry>>>>",receivedEntry); + ngbModal.dismissAll(); + if(receivedEntry.httpStatusCode===200){ + _self.getFunctionalMenu(); + } + }); + } + }); + } +} diff --git a/portal-FE-common/src/app/pages/functional-menu/jqTreeContextMenu.js b/portal-FE-common/src/app/pages/functional-menu/jqTreeContextMenu.js new file mode 100644 index 00000000..fa240187 --- /dev/null +++ b/portal-FE-common/src/app/pages/functional-menu/jqTreeContextMenu.js @@ -0,0 +1,195 @@ +(function ($) { + if (!$.fn.tree) { + throw "Error jqTree is not loaded."; + } + + $.fn.jqTreeContextMenu = function (menuElement, callbacks) { + // + // TODO: + // * Make sure the useContextMenu option is set in jqTree, either complain or set it automatically + // * Make menu fade in/out + // + var self = this; + var $el = this; + + // The jQuery object of the menu div. + var $menuEl = menuElement; + + // This hash holds all menu items that should be disabled for a specific node. + var nodeToDisabledMenuItems = {}; + + // Hide the menu div. + $menuEl.hide(); + + // Disable system context menu from beeing displayed. + $el.bind("contextmenu", function (e) { + e.preventDefault(); + return false; + }); + + // Handle the contextmenu event sent from jqTree when user clicks right mouse button. + $el.bind('tree.contextmenu', function (event) { + var x = event.click_event.pageX; + var y = event.click_event.pageY; + var yPadding = 5; + var xPadding = 5; + var menuHeight = $menuEl.height(); + var menuWidth = $menuEl.width(); + var windowHeight = $(window).height(); + var windowWidth = $(window).width(); + + if (menuHeight + y + yPadding > windowHeight) { + // Make sure the whole menu is rendered within the viewport. + y = y - menuHeight; + } + if (menuWidth + x + xPadding > windowWidth) { + // Make sure the whole menu is rendered within the viewport. + x = x - menuWidth; + } + + // Handle disabling and enabling of menu items on specific nodes. + if (Object.keys(nodeToDisabledMenuItems).length > 0) { + if (event.node.name in nodeToDisabledMenuItems) { + var nodeName = event.node.name; + var items = nodeToDisabledMenuItems[nodeName]; + if (items.length === 0) { + $menuEl.find('li').addClass('disabled'); + $menuEl.find('li > a').unbind('click'); + } else { + $menuEl.find('li > a').each(function () { + $(this).closest('li').removeClass('disabled'); + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').addClass('disabled'); + $(this).unbind('click'); + } + }); + } + } else { + $menuEl.find('li.disabled').removeClass('disabled'); + } + } + + // Must call show before we set the offset (offset can not be set on display: none elements). + $menuEl.show(); + + $menuEl.offset({ left: x, top: y }); + + var dismissContextMenu = function () { + $(document).unbind('click.jqtreecontextmenu'); + $el.unbind('tree.click.jqtreecontextmenu'); + $menuEl.hide(); + } + // Make it possible to dismiss context menu by clicking somewhere in the document. + $(document).bind('click.jqtreecontextmenu', function () { + dismissContextMenu(); + }); + + // Dismiss context menu if another node in the tree is clicked. + $el.bind('tree.click.jqtreecontextmenu', function (e) { + dismissContextMenu(); + }); + + // Make selection follow the node that was right clicked on. + var selectedNode = $el.tree('getSelectedNode'); + if (selectedNode !== event.node) { + $el.tree('selectNode', event.node); + } + + // Handle click on menu items, if it's not disabled. + var menuItems = $menuEl.find('li:not(.disabled) a'); + if (menuItems.length !== 0) { + menuItems.unbind('click'); + menuItems.click(function (e) { + e.stopImmediatePropagation(); + dismissContextMenu(); + var hrefAnchor = e.currentTarget.attributes.href.nodeValue; + var funcKey = hrefAnchor.slice(hrefAnchor.indexOf("#") + 1, hrefAnchor.length) + var callbackFn = callbacks[funcKey]; + if (callbackFn) { + callbackFn(event.node); + } + return false; + }); + } + }); + + this.disable = function () { + if (arguments.length === 0) { + // Called as: api.disable() + $menuEl.find('li:not(.disabled)').addClass('disabled'); + $menuEl.find('li a').unbind('click'); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 1) { + // Called as: api.disable(['edit','remove']) + var items = arguments[0]; + if (typeof items !== 'object') { + return; + } + $menuEl.find('li > a').each(function () { + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').addClass('disabled'); + $(this).unbind('click'); + } + }); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 2) { + // Called as: api.disable(nodeName, ['edit','remove']) + var nodeName = arguments[0]; + var items = arguments[1]; + nodeToDisabledMenuItems[nodeName] = items; + } + }; + + this.enable = function () { + if (arguments.length === 0) { + // Called as: api.enable() + $menuEl.find('li.disabled').removeClass('disabled'); + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 1) { + // Called as: api.enable(['edit','remove']) + var items = arguments[0]; + if (typeof items !== 'object') { + return; + } + + $menuEl.find('li > a').each(function () { + var hrefValue = $(this).attr('href'); + var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length) + if ($.inArray(value, items) > -1) { + $(this).closest('li').removeClass('disabled'); + } + }); + + nodeToDisabledMenuItems = {}; + } else if (arguments.length === 2) { + // Called as: api.enable(nodeName, ['edit','remove']) + var nodeName = arguments[0]; + var items = arguments[1]; + if (items.length === 0) { + delete nodeToDisabledMenuItems[nodeName]; + } else { + var disabledItems = nodeToDisabledMenuItems[nodeName]; + for (var i = 0; i < items.length; i++) { + var idx = disabledItems.indexOf(items[i]); + if (idx > -1) { + disabledItems.splice(idx, 1); + } + } + if (disabledItems.length === 0) { + delete nodeToDisabledMenuItems[nodeName]; + } else { + nodeToDisabledMenuItems[nodeName] = disabledItems; + } + } + if (Object.keys(nodeToDisabledMenuItems).length === 0) { + $menuEl.find('li.disabled').removeClass('disabled'); + } + } + }; + return this; + }; +} (jQuery)); |