diff options
Diffstat (limited to 'portal-FE-common/src/app/pages/widget-onboarding')
8 files changed, 1229 insertions, 0 deletions
diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.html b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.html new file mode 100644 index 00000000..bd87e699 --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.html @@ -0,0 +1,120 @@ +<!-- + ============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"> + <!--Modal Headers--> + <div class="modal-header"> + <h4 class="modal-title">Widget Details</h4> + <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross')"> + <span aria-hidden="true">×</span> + </button> + </div> + + <!--Modal Body goes here--> + <form id="widgets-details-form" name="widgetForm" [formGroup] = "uploadForm" (ngSubmit)="saveChanges()" + enctype="multipart/form-data" novalidate autocomplete="off"> + <div class="modal-body"> + <div class="widget-model-body"> + <div class="item-label">Widget Name</div> + <input id="widgets-details-input-name" class="widget-name-field" + type="text" formControlName="widgetName" [(ngModel)]="widget.name" + ng-pattern="/^[\w -]*$/" maxlength="100" + ng-disabled="widgetOnboardingDetails.isEditMode" required /> + + <div class="item-label" style="padding-top: 20px">Widget Description</div> + + <textarea b2b-reset b2b-reset-textarea class="widgets-details-input-desc" + formControlName="description" [(ngModel)]="widget.desc" type="text" maxlength="200"> + </textarea> + + <div class="table-dropdown"> + <mat-form-field class="widget-service-select"> + <mat-label> Service Endpoint </mat-label> + <mat-select name="widget-service-select" id="serviceEndPoint" + formControlName="serviceEndPoint" [(ngModel)]="widget.serviceURL" [disabled]="isEditMode"> + <mat-option *ngFor="let rowData of availableMicroServices" [value]="rowData.id" >{{rowData.option}}</mat-option> + </mat-select> + </mat-form-field> + </div> + + <div class="property-label checkbox-label" style="padding-top: 20px"> + <mat-checkbox formControlName="allowAllUser" type="checkbox" [(ngModel)]="widget.allUser" + id="allow-all-user"> + Allow all user access + </mat-checkbox> + </div> + + <div [hidden]="widget.allUser"> + <div class="table-dropdown"> + <mat-form-field class="widget-applications-select"> + <mat-label> Application Name </mat-label> + <mat-select multiple name="widget-application-select" id="application" + formControlName="applicationName" [(ngModel)]="widget.appName"> + <mat-option *ngFor="let rowData of availableApps" [value]="rowData.id" >{{rowData.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + + <div [hidden]="widget.allUser"> + <div class="table-dropdown"> + <mat-form-field class="widget-roles-select"> + <mat-label> User Role Name </mat-label> + <mat-select multiple name="widget-role-select" id="roles" + formControlName="applicationRole" [(ngModel)]="widget.widgetRoles"> + <mat-option *ngFor="let appRole of availableApps.roles" [value]="appRole.id" >{{appRole.name}}</mat-option> + </mat-select> + </mat-form-field> + </div> + </div> + + <div class="item-label widget-upload">Upload Widget</div> + <div> + <input id="widget-onboarding-details-upload-file" + name="profile" type="file" + class="widget-onboarding-details-upload-file ht" + (change)="onFileSelect($event)"/> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="submit" class="btn btn-primary"[disabled]="(isFileNotSelected && !isEditMode)">Save</button> + <button type="button" class="btn btn-primary" (click)="activeModal.close('Close')">Cancel</button> + </div> + </form> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.scss b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.scss new file mode 100644 index 00000000..7f5b871e --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.scss @@ -0,0 +1,82 @@ +/*- + * ============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: 700px; + width: 619px; + overflow-x: auto; + overflow-y: auto; +} + +::ng-deep .widget-applications-select { + width: 34em; +} + +::ng-deep .widget-roles-select { + width: 34em; + } + +::ng-deep .widget-service-select { + width: 34em; + } + +.widget-name-field{ + width: 22em; + margin-top: 5px; +} + +.widgets-details-input-desc { + overflow: auto; + resize: vertical; + width: 34em; + margin-top: 5px; +} + +.widget-upload{ + margin-top: 16px; +} + +#applicationName{ + width: 100%; + margin-top: 5px; +} + +#serviceEndPoint{ + width: 100%; + margin-top: 5px; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.spec.ts b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.spec.ts new file mode 100644 index 00000000..411da1e9 --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-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 { WidgetDetailsDialogComponent } from './widget-details-dialog.component'; + +describe('WidgetDetailsDialogComponent', () => { + let component: WidgetDetailsDialogComponent; + let fixture: ComponentFixture<WidgetDetailsDialogComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ WidgetDetailsDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WidgetDetailsDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.ts b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.ts new file mode 100644 index 00000000..a6d6115f --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-details-dialog/widget-details-dialog.component.ts @@ -0,0 +1,429 @@ +/*- + * ============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 { IWidget } from 'src/app/shared/model/widget-onboarding/widget'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { WidgetOnboardingService, MicroserviceService, AdminsService, ApplicationsService } from 'src/app/shared/services'; +import { FormBuilder, FormGroup, FormControl } from '@angular/forms'; +import { IMircroservies } from 'src/app/shared/model/microservice-onboarding/microservices'; +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-widget-details-dialog', + templateUrl: './widget-details-dialog.component.html', + styleUrls: ['./widget-details-dialog.component.scss'] +}) +export class WidgetDetailsDialogComponent implements OnInit { + @Input() public widget: IWidget; + @Input() public availableMicroServices: Array<IMircroservies>; + @Input() public applicationList: Array<Object>; + + @Output() passEntry: EventEmitter<any> = new EventEmitter(); + + widgetsList: any; + uploadForm: FormGroup; + result: any; + selected: any; + isEditMode: boolean = false; + hasSelectedApp: boolean = false; + availableApps = []; + availableRoles = []; + allRoleSelected: boolean = false; + appCounter = 0; + duplicatedName:boolean = true; + widgetFileTypeError:boolean = false; + isFileNotSelected:boolean = true; + + constructor(public widgetOnboardingService: WidgetOnboardingService, + public microservice: MicroserviceService, public applicationsService: ApplicationsService, + public formBuilder: FormBuilder, public activeModal: NgbActiveModal, + public ngbModal: NgbModal, public adminsService: AdminsService) { } + + ngOnInit() { + this.widget.allUser = true; + this.getOnboardingWidgets(); + this.getAvailableApps(); + this.duplicatedName = true; + this.allRoleSelected = false; + this.appCounter = 0; + this.uploadForm = this.formBuilder.group({ + profile: [''], + widgetName:[''], + description:[''], + serviceEndPoint:[''], + allowAllUser:[''], + applicationName:[''], + applicationRole:[''] + }); + + if(this.widget && this.widget.name){ + this.isEditMode = true; + } + if(this.isEditMode && this.widget && this.widget.allowAllUser == "Y"){ + this.widget.allUser = true; + }else if(this.isEditMode && this.widget && this.widget.allowAllUser == "N"){ + this.widget.allUser = false; + } + if(this.widget && this.widget.serviceId != null){ + this.widget.serviceURL = this.widget.serviceId; + } + } + + //Add Or Update Widget. + saveChanges(){ + if(this.widget.name == '' || this.widget.name == undefined){ + this.openConfirmationModal("Error",'Widget Name is required.'); + return; + } + + if(!this.isEditMode){ + this.updateWidgetName(); + } + + if(this.duplicatedName == false){ + this.openConfirmationModal("Error",'Name not available - please choose different name.'); + return; + } + + if(this.widgetFileTypeError == true){ + this.openConfirmationModal("Error",'File must be .zip'); + return; + } + + let widgetName = this.widget.name; + let description = this.widget.desc + let file_loc = widgetName + ".zip"; + const formData = new FormData(); + formData.append('file', this.uploadForm.get('profile').value); + //console.log("FormData >>>>::> ",formData.get('file')); + + /*if((formData == undefined && !this.isEditMode) || + (!this.widget.allUser && this.appCounter == 0) || + this.widget.name == null || + (!this.widget.allUser && !this.allRoleSelected)){ + console.log("return from 2nd check"); + return; + }*/ + + let selectedRoles = []; + + if(!this.widget.allUser){ + for(var i = 0; i < this.availableApps.length; i++){ + if(this.availableApps[i].isSelected){ + for(var n = 0; n < this.availableApps[i].roles.length; n++) { + if(this.availableApps[i].roles[n].isSelected){ + var role = { + app: {appId: this.availableApps[i].id}, + roleId: this.availableApps[i].roles[n].id, + roleName: this.availableApps[i].roles[n].name, + }; + selectedRoles.push(role); + } + } + } + } + } + + let allowAllUser = 0; + if(this.widget.allUser){ + allowAllUser = 1; + } + + let serviceId = null; + if(this.widget.serviceURL != null && this.widget.serviceURL != undefined){ + serviceId = parseInt(this.widget.serviceURL); + } + var newWidget = { + name: widgetName, + desc: description, + widgetRoles: selectedRoles, + fileLocation: file_loc, + allowAllUser: allowAllUser, + serviceId: serviceId + }; + + if(this.isEditMode){ + //console.log("widget in updateWidget :::: >>> ",newWidget); + if(formData && formData.get('file')){ + this.widgetOnboardingService.updateWidgetWithFile(formData, this.widget.id, newWidget) + .subscribe( _data => { + this.result = 'updated'; + this.passEntry.emit(this.result); + }, error => { + console.log(error); + this.openConfirmationModal("Error",'Could not update. Please retry.'); + }); + }else{ + this.widgetOnboardingService.updateWidget(this.widget.id, newWidget) + .subscribe( _data => { + this.result = 'updated'; + this.passEntry.emit(this.result); + }, error => { + this.openConfirmationModal("Error",'Could not update. Please retry.'); + console.log(error); + }); + } + }else{ + //console.log("newWidget in createWidget :::: >>> ",newWidget); + this.widgetOnboardingService.createWidget(newWidget, formData) + .subscribe( _data => { + this.result = 'created'; + this.passEntry.emit(this.result); + }, error => { + this.openConfirmationModal("Error",'Could not save. Please retry.'); + console.log(error); + }); + } + this.ngbModal.dismissAll(); + } + + onFileSelect(event) { + this.widgetFileTypeError = false; + this.isFileNotSelected = false; + if (event.target.files.length > 0) { + const file = event.target.files[0]; + //console.log("onFileSelect called.. ",file); + var fileName = file.name; + var validFormats = ['zip']; + var ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase(); + if(validFormats.indexOf(ext) == -1){ + this.widgetFileTypeError = true; + } + this.uploadForm.get('profile').setValue(file); + } + } + + appUpdate(){ + this.hasSelectedApp = false; + this.appCounter = 0; + for(var i = 0; i < this.availableApps.length; i++){ + if(this.availableApps[i].isSelected){ + this.appCounter++; + if(!this.hasSelectedApp) + this.hasSelectedApp = true; + } + if(this.availableApps[i].isSelected + && this.availableApps[i].roles.length == 0){ + var index = i; + this.availableRoles = []; + this.adminsService.getRolesByApp(this.availableApps[i].id) + .subscribe( roles => { + if(roles && roles.length >0){ + for(var i = 0; i < roles.length; i++){ + this.availableRoles.push({ + id: roles[i].id, + name: roles[i].name, + isSelected: false, + }); + } + } + this.availableApps[index].roles = this.availableRoles; + }, error => { + console.log(error); + }); + } + } + this.allRoleSelected = true; + this.checkRoleSelected(); + } + + roleUpdate(app){ + this.allRoleSelected = true; + for(var i = 0; i < app.roles.length; i++){ + if(app.roles[i].isSelected){ + app.roleSelected = true; + this.checkRoleSelected(); + return; + } + } + app.roleSelected = false; + this.checkRoleSelected(); + } + + checkRoleSelected(){ + for(var i = 0; i < this.availableApps.length; i++){ + if(this.availableApps[i].isSelected + && !this.availableApps[i].roleSelected){ + this.allRoleSelected = false; + return; + } + } + } + + getAppName = function(appId){ + for(var i = 0; i < this.availableApps.length; i++){ + if(this.availableApps[i].id == appId){ + return this.availableApps[i].name; + } + } + } + + updateWidgetName(){ + for(var i = 0; i < this.widgetsList.length; i++){ + if(this.widget.name && this.widget.name.toUpperCase() == this.widgetsList[i].name.toUpperCase()){ + this.duplicatedName = false; + return; + } + } + this.duplicatedName = true; + } + + getOnboardingWidgets(){ + this.widgetOnboardingService.getManagedWidgets() + .subscribe(_data => { + this.result = _data + if(!(_data instanceof Array)){ + return; + } + if (this.result == null || this.result == 'undefined') { + console.log('WidgetOnboardingService::getOnboardingWidgets Failed: Result or result.data is null'); + }else { + this.widgetsList = _data; + } + }, error =>{ + console.log(error); + }); + } + + getAvailableApps(){ + if(this.isEditMode == false){ + this.availableApps=[]; + this.applicationsService.getAppsForSuperAdminAndAccountAdmin() + .subscribe(apps => { + this.availableApps=[]; + for(var i=0;i<apps.length;i++) { + if (!apps[i].restrictedApp) { + this.availableApps.push({ + id: apps[i].id, + name: apps[i].name, + roles: [], + roleSelected: false, + isSelected: false, + }); + } + } + }, error =>{ + console.log(error); + }); + }else if(this.isEditMode == true){ + if(this.widget.allowAllUser == "Y"){ + this.widget.allUser = true; + } + this.applicationsService.getAppsForSuperAdminAndAccountAdmin() + .subscribe(apps => { + this.availableApps=[]; + let selectedApps = {}; + var availableApps = this.availableApps; + this.allRoleSelected = true; + for(var i=0; i < this.widget.widgetRoles.length; i++){ + if(selectedApps[this.widget.widgetRoles[i].app.appId] != undefined) + selectedApps[this.widget.widgetRoles[i].app.appId] += this.widget.widgetRoles[i].roleId + ";" + this.widget.widgetRoles[i].roleName + ";"; + else{ + selectedApps[this.widget.widgetRoles[i].app.appId] = this.widget.widgetRoles[i].roleId + ";" + this.widget.widgetRoles[i].roleName + ";"; + this.appCounter++; + } + } + apps.forEach(function(app, index){ + availableApps.push({ + id: app.id, + name: app.name, + roles: [], + roleSelected: false, + isSelected: false, + }); + if(selectedApps[app.id] != undefined){ + this.adminsService.getRolesByApp(app.id) + .subscribe(roles => { + var role = selectedApps[app.id].split(';'); + var selectedRoles = []; + var n = 0; + while((n+1) < role.length){ + selectedRoles.push({ + id: role[n++], + name: role[n++], + isSelected: true, + }); + } + for(var m = 0; m < roles.length; m++){ + var hasSelected = true; + for(var n = 0; n < selectedRoles.length; n++){ + if(selectedRoles[n].id == roles[m].id){ + hasSelected = false; + break; + } + } + if(hasSelected){ + selectedRoles.push({ + id: roles[m].id, + name: roles[m].name, + isSelected: false, + }); + } + } + availableApps[index].roleSelected = true; + availableApps[index].isSelected = true; + availableApps[index].roles = selectedRoles; + }, error =>{ + console.log(error); + }); + } + }) + + }, error =>{ + console.log(error); + }); + } + //console.log("this.availableApps :: ",this.availableApps); + } + + 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/widget-onboarding/widget-onboarding.component.html b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.html new file mode 100644 index 00000000..43065545 --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.html @@ -0,0 +1,100 @@ +<!-- + ============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 class="ecomp-main-view-title"> + <h1>Widget Onboarding</h1> + </div> + + <div class="c-ecomp-abs-select default"> + <div class="table-dropdown"> + <mat-form-field class="widget-application-select"> + <mat-label> Select Application </mat-label> + <mat-select name="widget-application-select" [(ngModel)]="filterByApp" #appId="ngModel" (ngModelChange)="applyAppFilter($event)"> + <mat-option *ngFor="let rowData of applicationList" [value]="rowData">{{rowData.title}}</mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field> + <input matInput type="text" (keyup)="applyFilter($event.target.value)" placeholder="Search in entire table"> + </mat-form-field> + + <button type="button" class="btn btn-primary" (click)="openAddWigetModal('')"> + <i class="icon ion-md-person-add"></i>Add Widget + </button> + </div> + </div> + + <table mat-table [dataSource]="dataSource" matSort> + <!-- Wiget Name Column --> + <ng-container matColumnDef="widgetName"> + <th id="col1" mat-header-cell *matHeaderCellDef> Widget Name </th> + <td (click)="openAddWigetModal(element)" id="rowheader_t1_{{i}}-widgetName" + mat-cell *matCellDef="let element; let i = index;"> {{element.name}} + </td> + </ng-container> + + <!-- Application Name Column --> + <ng-container matColumnDef="application"> + <th id="col2" mat-header-cell *matHeaderCellDef> Application </th> + <td (click)="openAddWigetModal(element)" id="rowheader_t1_{{i}}-application" + mat-cell *matCellDef="let element; let i=index;"> {{element.appContent}} </td> + </ng-container> + + <!-- Download URL --> + <ng-container matColumnDef="download"> + <th id="col3" mat-header-cell *matHeaderCellDef> Download </th> + <td id="rowheader_t1_{{$index}}-download" mat-cell *matCellDef="let element; let i=index;"> + <i class="icon ion-md-download" (click)="downloadWidget(element)"></i> + </td> + </ng-container> + + <!-- Delete Column --> + <ng-container matColumnDef="delete"> + <th id="col4" mat-header-cell *matHeaderCellDef> Delete </th> + <td id="rowheader_t1_{{i}}" mat-cell *matCellDef="let element; let i=index;"> + <span class="icon-trash" id="{{i}}-button-portal-admin-remove" (click)="removeWidget(element)"> + <i class="icon ion-md-trash"></i> + </span> + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + </table> + <mat-paginator [pageSizeOptions]="[10, 20]" showFirstLastButtons></mat-paginator> +</div> diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.scss b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.scss new file mode 100644 index 00000000..b87b7abf --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.scss @@ -0,0 +1,62 @@ +/*- + * ============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============================================ + * + * + */ + +.container th{ + padding-bottom: 15px; + font-weight: bold; +} + +::ng-deep .mat-form-field-infix { + width: 200px; +} + +::ng-deep .widget-application-select { + display: inline-block; + position: relative; + text-align: left; + margin-left: 10px; + margin-right: 110px; +} + +.ion-md-download{ + cursor: pointer; +} + +.ion-md-trash{ + cursor: pointer; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.spec.ts b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.spec.ts new file mode 100644 index 00000000..2fd7ef27 --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.spec.ts @@ -0,0 +1,62 @@ +/*- + * ============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 { WidgetOnboardingComponent } from './widget-onboarding.component'; + +describe('WidgetOnboardingComponent', () => { + let component: WidgetOnboardingComponent; + let fixture: ComponentFixture<WidgetOnboardingComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ WidgetOnboardingComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WidgetOnboardingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.ts b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.ts new file mode 100644 index 00000000..d87791f6 --- /dev/null +++ b/portal-FE-common/src/app/pages/widget-onboarding/widget-onboarding.component.ts @@ -0,0 +1,311 @@ +/*- + * ============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, ViewChild, Input, ChangeDetectionStrategy } from '@angular/core'; +import { MatTableDataSource } from '@angular/material'; +import { MatSort, MatPaginator } from '@angular/material'; +import { WidgetOnboardingService, MicroserviceService } from '../../shared/services/index'; +import { IMircroservies } from 'src/app/shared/model/microservice-onboarding/microservices'; +import { IWidget } from 'src/app/shared/model/widget-onboarding/widget'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { HttpClient } from '@angular/common/http'; +import { WidgetDetailsDialogComponent } from './widget-details-dialog/widget-details-dialog.component'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-widget-onboarding', + templateUrl: './widget-onboarding.component.html', + styleUrls: ['./widget-onboarding.component.scss'] +}) +export class WidgetOnboardingComponent implements OnInit { + + widgetsList: Array<IWidget> = []; + applicationList: Array<Object> = []; + availableMicroServices: Array<IMircroservies> = []; + displayedColumns: string[] = ['widgetName', 'application', 'download','delete']; + isCommError: boolean = false; + dataSource = new MatTableDataSource(this.widgetsList); + @ViewChild(MatSort) sort: MatSort; + @ViewChild(MatPaginator) paginator: MatPaginator; + + isEditMode: boolean = false; + result: any; + + + constructor( public widgetOnboardingService: WidgetOnboardingService, + public microservice: MicroserviceService,public ngbModal: NgbModal) { } + + ngOnInit() { + this.prepareApplicationRoleName(); + this.getOnboardingWidgets(); + this.populateAvailableApps(); + this.getAvailableMicroServices(); + } + + getOnboardingWidgets(){ + this.isCommError = false; + this.widgetOnboardingService.getManagedWidgets() + .subscribe(_data => { + this.result = _data + if(!(_data instanceof Array)){ + this.isCommError = true; + return; + } + //console.log("getOnboardingWidgets Data :: ", _data); + if (this.result == null || this.result == 'undefined') { + console.log('WidgetOnboardingService::getOnboardingWidgets Failed: Result or result.data is null'); + }else { + let reSortedWidget = _data.sort(this.getSortOrder("name")); + this.widgetsList = reSortedWidget; + this.prepareApplicationRoleName(); + this.populateTableData(this.widgetsList); + } + }, error =>{ + console.log(error); + }); + } + + //Refactor this into a directive + getSortOrder(prop){ + return function(a, b) { + if (a[prop].toLowerCase() > b[prop].toLowerCase()) { + return 1; + } else if (a[prop].toLowerCase() < b[prop].toLowerCase()) { + return -1; + } + return 0; + } + } + + removeWidget(widget: IWidget) { + let confirmationMsg = 'You are about to delete this Widget : ' + widget.name+ '. Click OK to continue.'; + this.openInformationModal("Confirmation",confirmationMsg).result.then((result) => { + if (result === 'Ok') { + if(!widget || widget == null){ + console.log('WidgetOnboardingCtrl::deleteService: No widget or ID... cannot delete'); + return; + } + + this.widgetsList.splice(this.widgetsList.indexOf(widget), 1); + + this.widgetOnboardingService.deleteWidget(widget.id) + .subscribe( _data => { + this.result = _data; + this.openConfirmationModal("Success",'Widget deleted successfully'); + }, error => { + console.log(error); + }); + + this.populateTableData(this.widgetsList); + } + }, (resut) => { + this.openConfirmationModal('Error', resut); + return; + }) + } + + + openAddWigetModal(rowData:any){ + //console.log("openAddWigetModal getting called..."); + const modalRef = this.ngbModal.open(WidgetDetailsDialogComponent, { size: 'lg' }); + modalRef.componentInstance.widget = rowData; + modalRef.componentInstance.availableMicroServices = this.availableMicroServices; + modalRef.componentInstance.applicationList = this.applicationList; + modalRef.componentInstance.widgetsList = this.widgetsList; + if(rowData != 'undefined' && rowData){ + this.isEditMode = true; + }else{ + modalRef.componentInstance.widget = {}; + this.isEditMode = false; + } + modalRef.componentInstance.passEntry.subscribe((receivedEntry: any) => { + //console.log("receivedEntry >>> ",receivedEntry); + if(receivedEntry){ + this.widgetsList = []; + this.getOnboardingWidgets(); + } + }); + } + + applyFilter(filterValue: string) { + this.dataSource.filter = filterValue.trim().toLowerCase(); + } + + applyAppFilter(event) { + let filterByApp = event.title; + if(filterByApp == 'All Applications'){ + this.getOnboardingWidgets(); + }else{ + this.dataSource.filter = filterByApp.trim().toLowerCase(); + } + } + + downloadWidget(widget){ + this.widgetOnboardingService.downloadWidgetFile(widget.id) + .subscribe(res => { + var data = res; + //console.log("downloadWidgetFile response :: ",data); + var filename = widget.name + ".zip"; + if (data == undefined || data == null){ + this.openConfirmationModal("Could not download. Please retry.", ''); + return; + } + var a = document.createElement('a'); + var blob = new Blob([data], {type: 'application/octet-stream'}); + var url = window.URL.createObjectURL(blob); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + + setTimeout(function(){ + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 100); + + }, error =>{ + console.log(error); + this.openConfirmationModal("Could not download. Please retry.", error.message); + }); + } + + + populateTableData(wigetList: Array<IWidget>){ + this.dataSource = new MatTableDataSource(wigetList); + this.dataSource.sort = this.sort; + this.dataSource.paginator = this.paginator; + }; + + prepareApplicationRoleName(){ + if(this.widgetsList && this.widgetsList.length > 0){ + for(var i = 0; i < this.widgetsList.length; i++){ + let set = new Set(); + var info = ""; + var appContent = []; + var appName = []; + if(this.widgetsList[i].widgetRoles && this.widgetsList[i].widgetRoles.length >0){ + for(var n = 0; n < this.widgetsList[i].widgetRoles.length; n++){ + if(this.widgetsList[i].widgetRoles[n].app) + set.add(this.widgetsList[i].widgetRoles[n].app.appName); + } + set.forEach(function (item) { + info = item.toString() + " - "; + for(var n = 0; n < this.widgetsList[i].widgetRoles.length; n++){ + if(this.widgetsList[i].widgetRoles[n].app && item.toString() == this.widgetsList[i].widgetRoles[n].app.appName){ + info += this.widgetsList[i].widgetRoles[n].roleName + "; "; + } + } + appContent.push(info); + appName.push(item.toString()); + }.bind(this)); + } + if(this.widgetsList[i].allowAllUser == "Y"){ + info = "All Applications"; + appContent.push("All Applications"); + appName.push("All Applications"); + } + this.widgetsList[i].appContent = appContent; + this.widgetsList[i].appName = appName; + } + } + } + + populateAvailableApps(){ + this.widgetOnboardingService.populateAvailableApps() + .subscribe( _data => { + this.applicationList.push({ + index: 0, + title: 'All Applications', + value: '' + }) + var reSortedApp = _data.sort(this.getSortOrder("name")); + var realAppIndex = 1; + for (let i = 1; i <= reSortedApp.length; i++) { + if (!reSortedApp[i-1].restrictedApp) { + if(_data[i - 1].name && _data[i - 1].name!=""){ + this.applicationList.push({ + index: realAppIndex, + title: _data[i - 1].name, + value: _data[i - 1].id + }) + } + realAppIndex = realAppIndex + 1; + } + } + }, error => { + console.log(error); + }); + } + + getAvailableMicroServices = () =>{ + this.availableMicroServices = []; + this.microservice.getServiceList() + .subscribe(_data => { + this.result = _data; + if (this.result == null || this.result == 'undefined') { + console.log('MicroserviceService::getAvailableMicroServices Failed: Result or result.data is null'); + }else { + for(var i = 0; i < _data.length; i++){ + this.availableMicroServices.push({ + id: _data[i].id, + name: _data[i].name, + option: _data[i].name + ": " + _data[i].url + }); + } + } + }, error =>{ + console.log(error); + }); + } + + 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; + } + +} |