diff options
Diffstat (limited to 'portal-FE-common/src/app/pages/role')
20 files changed, 3084 insertions, 0 deletions
diff --git a/portal-FE-common/src/app/pages/role/add-role/add-role.component.html b/portal-FE-common/src/app/pages/role/add-role/add-role.component.html new file mode 100644 index 00000000..e3393a81 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/add-role/add-role.component.html @@ -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============================================ + + + --> + + <div class="container"> + <div class="modal-header"> + <h4 class="modal-title">{{title}}</h4> + <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross')"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <span class="onap-spinner" *ngIf="showSpinner"></span> + <div class="input-group"> + <div class="input-group-prepend"> + <span class="input-group-text">Name</span> + </div> + <input type="text" aria-label="name" maxlength="300" [(ngModel)]="role.name" placeholder="Enter name..." + [value]="role.name" class="form-control"> + </div> + + <div class="input-group"> + <div class="input-group-prepend"> + <span class="input-group-text">Priority</span> + </div> + <input type="text" aria-label="priority" maxlength="300" [(ngModel)]="role.priority" [value]="role.priority" + placeholder="Enter priority..." class="form-control"> + </div> + <br> + <div *ngIf="showGlobalRole" class="form-check" style="text-align:right;"> + <mat-checkbox class="example-margin" [(ngModel)]="isGlobalRoleChecked.isChecked"> Global Role </mat-checkbox> + </div> + <div class="role-function-list" *ngIf="dialogState === 2"> + <table mat-table [dataSource]="roleFunctionsDataSource"> + <!-- Active Column --> + <ng-container matColumnDef="active"> + <th id="col3" mat-header-cell *matHeaderCellDef> </th> + <td id="rowheader_t1_{{i}}-userId" mat-cell *matCellDef="let element; let i=index;"> + <mat-slide-toggle [(ngModel)]="element.selected" (change)="toggleRoleFunction(element)"></mat-slide-toggle> + </td> + </ng-container> + + <!-- Function Name Column --> + <ng-container matColumnDef="name"> + <th id="col2" mat-header-cell *matHeaderCellDef > Function Name </th> + <td id="rowheader_t1_{{i}}-lastName" mat-cell *matCellDef="let element; let i=index;"> + {{element.name}} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + </table> + </div> + </div> + <div class="modal-footer"> + <button type="submit" class="btn btn-primary" [disabled]="!role.name || showSpinner" + (click)="saveRole()">Save</button> + <button type="button" class="btn btn-primary" (click)="activeModal.close('Close')">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/add-role/add-role.component.scss b/portal-FE-common/src/app/pages/role/add-role/add-role.component.scss new file mode 100644 index 00000000..54f59fcd --- /dev/null +++ b/portal-FE-common/src/app/pages/role/add-role/add-role.component.scss @@ -0,0 +1,45 @@ +/*- + * ============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============================================ + * + * + */ +.onap-spinner { + z-index: 9999; +} + +.role-function-list{ + overflow-y: auto; + height: 500px; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/add-role/add-role.component.spec.ts b/portal-FE-common/src/app/pages/role/add-role/add-role.component.spec.ts new file mode 100644 index 00000000..1104010d --- /dev/null +++ b/portal-FE-common/src/app/pages/role/add-role/add-role.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 { AddRoleComponent } from './add-role.component'; + +describe('AddRoleComponent', () => { + let component: AddRoleComponent; + let fixture: ComponentFixture<AddRoleComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddRoleComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddRoleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/role/add-role/add-role.component.ts b/portal-FE-common/src/app/pages/role/add-role/add-role.component.ts new file mode 100644 index 00000000..5c0a376e --- /dev/null +++ b/portal-FE-common/src/app/pages/role/add-role/add-role.component.ts @@ -0,0 +1,190 @@ +/*- + * ============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 { RoleService } from 'src/app/shared/services'; +import { environment } from 'src/environments/environment'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { Role } from 'src/app/shared/model'; +import { MatTableDataSource } from '@angular/material'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; + +@Component({ + selector: 'app-add-role', + templateUrl: './add-role.component.html', + styleUrls: ['./add-role.component.scss'] +}) +export class AddRoleComponent implements OnInit { + + @Input() title: string; + @Input() appId: string; + @Input() dialogState: number; + @Input() availableRole: any; + @Input() appRoleFunctions: any; + @Output() passBackAddRolePopup: EventEmitter<any> = new EventEmitter(); + availableRoleFunctions: any; + isGlobalRoleChecked = { + isChecked: false + } + role: Role; + roleFunctions: any; + showGlobalRole: boolean; + api = environment.api; + showSpinner: boolean; + displayedColumns: string[] = ['active', 'name']; + roleFunctionsDataSource = new MatTableDataSource(this.roleFunctions); + finalSelectedRoleFunctions: any; + constructor(public activeModal: NgbActiveModal, public ngbModal: NgbModal, private roleService: RoleService, public http: HttpClient) { } + + ngOnInit() { + this.role = new Role; + this.finalSelectedRoleFunctions = []; + if (this.appId == '1') + this.showGlobalRole = true; + if (this.dialogState === 2) { + this.isGlobalRoleChecked.isChecked = (this.availableRole.name.includes('global_')) ? true : false; + this.availableRoleFunctions = []; + this.role = this.availableRole; + this.roleFunctionsDataSource = new MatTableDataSource(this.setSelectedRoleFucntions()); + } + } + + setSelectedRoleFucntions() { + for (var i = 0; i < this.appRoleFunctions.length; i++) { + var availableRoleFunction = this.appRoleFunctions[i]; + availableRoleFunction['selected'] = false; + for (var j = 0; j < this.availableRole.roleFunctions.length; j++) { + if (availableRoleFunction.code === this.availableRole.roleFunctions[j].code + && availableRoleFunction.type === this.availableRole.roleFunctions[j].type + && availableRoleFunction.action === this.availableRole.roleFunctions[j].action) { + availableRoleFunction.selected = true; + console.log(availableRoleFunction.selected); + } + } + this.availableRoleFunctions.push(availableRoleFunction); + } + return this.availableRoleFunctions; + } + + toggleRoleFunction(_element) { + if (this.appRoleFunctions) { + for (var i = 0; i < this.appRoleFunctions.length; i++) { + var availableRoleFunction = this.appRoleFunctions[i]; + if (availableRoleFunction.selected && !this.finalSelectedRoleFunctions.includes(availableRoleFunction)) { + this.finalSelectedRoleFunctions.push(availableRoleFunction); + } + } + } + if (!_element.selected) { + for (var i = 0; i < this.finalSelectedRoleFunctions.length; i++) { + var availableRoleFunction = this.finalSelectedRoleFunctions[i]; + if (availableRoleFunction.code == _element.code + && availableRoleFunction.type == _element.type + && availableRoleFunction.action == _element.action) { + this.finalSelectedRoleFunctions.splice(i, 1); + } + } + } + } + + + + saveRole() { + var uuu = this.api.saveRole.replace(':appId', this.appId); + if (this.isGlobalRoleChecked.isChecked) { + this.role.name = (this.role.name.indexOf('global_') == -1) ? ('global_' + this.role.name) : (this.role.name); + this.saveOrUpdateRole(uuu); + } else { + var roleName = this.role.name.toLowerCase(); + if (roleName.includes('global_')) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = 'Global prefix:"global_" can only be used when the global flag is checked for the role name:' + this.role.name + '. Please try again!'; + } else { + this.role.childRoles = []; + this.role.roleFunctions = []; + this.saveOrUpdateRole(uuu); + } + } + } + + saveOrUpdateRole(uuu) { + var confirmMessage = (this.dialogState === 2) ? 'You are about to update the role/role functions. Do you want to continue?' : 'You are about to create the role `' + this.role.name + '` . Do you want to continue?'; + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = confirmMessage; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') { + //overriding the final list of rolefunctions to role + if (this.finalSelectedRoleFunctions.length > 0) + this.role.roleFunctions = this.finalSelectedRoleFunctions; + var postData = { + role: this.role, + childRoles: this.role.childRoles, + roleFunctions: this.role.roleFunctions + }; + this.showSpinner = true + this.http.post(uuu, postData).toPromise().then((res: any) => { + this.showSpinner = false; + if (res && res.role) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = 'Success'; + modalInfoRef.componentInstance.message = 'Update Successful.'; + this.passBackAddRolePopup.emit(this.appId); + + } + else { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = 'Error'; + modalInfoRef.componentInstance.message = res.error; + } + }, (res: HttpErrorResponse) => { + this.showSpinner = false; + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = 'Error'; + modalInfoRef.componentInstance.message = 'Error while saving.' + res.status; + } + ); + } + }, (_dismiss) => { + + }) + } + +} diff --git a/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.html b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.html new file mode 100644 index 00000000..e9c7bd2d --- /dev/null +++ b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.html @@ -0,0 +1,323 @@ +<!-- + ============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="modal-header"> + <h4 class="modal-title">{{title}}</h4> + <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross')"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <div *ngIf="dialogState === 1"> + <mat-form-field> + <mat-label> Select Upload Type: </mat-label> + <mat-select [(ngModel)]="selectedUploadDropdown"> + <mat-option *ngFor="let uploadOpt of ngRepeatBulkUploadOptions" [value]="uploadOpt"> + {{uploadOpt.title}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div *ngIf="dialogState === 2"> + <div class="upload-instructions">Select Upload File:</div> + <!-- input type=file is difficult to style. + Instead use a label styled as a button. --> + <label class="file-label"> + <input type="file" (change)="onFileSelect($event.target)" accept="text/plain,.csv" /> + </label>{{selectedFile}} + <div *ngIf="selectedUploadDropdown.value === 'functions'" class="upload-instructions">File must be .csv or .txt + and one entry per line with this format: + <pre>Function Type, Function Instance, Function Action, Function Name</pre> + </div> + <div *ngIf="selectedUploadDropdown.value === 'roles'" class="upload-instructions">File must be .csv or .txt and + one entry per line with this format: + <pre>Role Name, Priority (Optional)</pre> + </div> + <div *ngIf="selectedUploadDropdown.value === 'roleFunctions'" class="upload-instructions">File must be .csv or + .txt and one entry per line with this format: + <pre>Role Name, Function Type, Function Instance, Function Action, Function Name</pre> + </div> + <div *ngIf="selectedUploadDropdown.value === 'globalRoleFunctions'" class="upload-instructions">File must be .csv + or .txt and one entry per line with this format: + <pre>Global Role Name, Function Type, Function Instance, Function Action, Function Name</pre> + </div> + </div> + <div class="bulk-upload" *ngIf="dialogState === 3"> + + <div *ngIf="selectedUploadDropdown.value === 'roles' && !isProcessing">Click OK to upload the valid + roles. Invalid or existing roles will be ignored. + <p style="font-size: 80%;"> + <span id="required" style="color: Red;" visible="false">*</span>Name can only contain alphanumeric + characters, dots(.), forward slashes(/), and underscores(_) + </p> + </div> + + <div *ngIf="selectedUploadDropdown.value === 'functions' && !isProcessing">Click OK to upload the valid + functions. Invalid or existing functions will be ignored. + <p style="font-size: 80%;"> + <span id="required" style="color: Red; font-size: 180%;" visible="false">*</span>Type can only contain + alphanumeric + characters, dots(.) and underscores(_) + </p> + <p style="font-size: 80%;"> + <span id="required" style="color: Red; font-size: 180%;" visible="false">*</span>Action can only contain + alphanumeric + characters, hyphens(-), dots(.) and underscores(_) and single + asterisk character(*) + </p> + <p style="font-size: 80%;"> + <span id="required" style="color: Red; font-size: 180%;" visible="false">*</span>Instance/Code can only + contain alphanumeric + characters, hyphens(-), dots(.), colons(:), forwardSlash(/) , + asterisk(*) and underscores(_) + </p> + <p style="font-size: 80%;"> + <span id="required" style="color: Red; font-size: 180%;" visible="false">*</span>Name can only contain + alphanumeric + characters, spaces, hyphens(-), dots(.) and underscores(_) + </p> + </div> + + <div *ngIf="selectedUploadDropdown.value === 'roleFunctions' && !isProcessing">Click OK to upload the valid + role functions. Invalid or existing functions will be ignored. + </div> + <div *ngIf="selectedUploadDropdown.value === 'globalRoleFunctions' && !isProcessing">Click OK to upload the valid + global role functions. Invalid or existing functions will be ignored. + </div> + <!-- progress indicator --> + <div class="upload-instructions" [hidden]="!isProcessing"> + {{progressMsg}} + <br> + <br> + <span class="onap-spinner"></span> + </div> + + <!-- progress indicator --> + <div class="upload-instructions" [hidden]="!isProcessedRecords"> + {{conformMsg}} + </div> + <div [hidden]="isProcessing || isProcessedRecords"> + + <table [hidden]="selectedUploadDropdown.value !== 'functions'" mat-table + [dataSource]="uploadFunctionsDataSource"> + + <ng-container matColumnDef="line"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Line + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;">{{element.line}} + </td> + </ng-container> + <ng-container matColumnDef="type"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Type + <td id="rowheader_t1_{{i}}-roles" mat-cell *matCellDef="let element; let i=index;"> + {{element.type}} + </td> + </ng-container> + <ng-container matColumnDef="instance"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Instance/Code + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.instance }} + </td> + </ng-container> + <ng-container matColumnDef="action"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Action + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.action}} + </td> + </ng-container> + <ng-container matColumnDef="name"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Name + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.name}} + </td> + </ng-container> + <ng-container matColumnDef="status"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Status + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.status}} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedFunctionColumns; sticky: true"></tr> + <tr mat-row id="table-row-{{i}}" *matRowDef="let row; columns: displayedFunctionColumns; let i = index;"></tr> + </table> + + <table [hidden]="selectedUploadDropdown.value !== 'roles'" mat-table [dataSource]="uploadRolesDataSource"> + + <ng-container matColumnDef="line"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Line + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;">{{element.line}} + </td> + </ng-container> + <ng-container matColumnDef="name"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Name + <td id="rowheader_t1_{{i}}-roles" mat-cell *matCellDef="let element; let i=index;"> + {{element.name}} + </td> + </ng-container> + <ng-container matColumnDef="priority"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Priority + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.priority}} + </td> + </ng-container> + <ng-container matColumnDef="status"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Status + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.status}} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedRoleColumns; sticky: true"></tr> + <tr mat-row id="table-row-{{i}}" *matRowDef="let row; columns: displayedRoleColumns; let i = index;"></tr> + </table> + + + <table [hidden]="selectedUploadDropdown.value !== 'roleFunctions'" mat-table + [dataSource]="uploadRoleFunctionsDataSource"> + + <ng-container matColumnDef="line"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Line + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;">{{element.line}} + </td> + </ng-container> + <ng-container matColumnDef="role"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Role Name + <td id="rowheader_t1_{{i}}-roles" mat-cell *matCellDef="let element; let i=index;"> + {{element.role}} + </td> + </ng-container> + <ng-container matColumnDef="type"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Type + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.type}} + </td> + </ng-container> + <ng-container matColumnDef="instance"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Instance + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.instance}} + </td> + </ng-container> + <ng-container matColumnDef="action"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Action + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.action}} + </td> + </ng-container> + <ng-container matColumnDef="name"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Name + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.name}} + </td> + </ng-container> + <ng-container matColumnDef="status"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Status + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.status}} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedRoleFunctionColumns; sticky: true"></tr> + <tr mat-row id="table-row-{{i}}" *matRowDef="let row; columns: displayedRoleFunctionColumns; let i = index;"> + </tr> + </table> + + <table [hidden]="selectedUploadDropdown.value !== 'globalRoleFunctions'" mat-table + [dataSource]="uploadGlobalRoleFunctionsDataSource"> + + <ng-container matColumnDef="line"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Line + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;">{{element.line}} + </td> + </ng-container> + <ng-container matColumnDef="role"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Global Role Name + <td id="rowheader_t1_{{i}}-roles" mat-cell *matCellDef="let element; let i=index;"> + {{element.role}} + </td> + </ng-container> + <ng-container matColumnDef="type"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Type + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.type}} + </td> + </ng-container> + <ng-container matColumnDef="instance"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Instance + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.instance}} + </td> + </ng-container> + <ng-container matColumnDef="action"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Action + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.action}} + </td> + </ng-container> + <ng-container matColumnDef="name"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef>Function Name + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.name}} + </td> + </ng-container> + <ng-container matColumnDef="status"> + <th id="rowheader-result" mat-header-cell *matHeaderCellDef> Status + <td id="table-data-{{i}}" mat-cell *matCellDef="let element; let i = index;"> + {{element.status}} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedGlobalRoleFunctionColumns; sticky: true"></tr> + <tr mat-row id="table-row-{{i}}" + *matRowDef="let row; columns: displayedGlobalRoleFunctionColumns; let i = index;"></tr> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="submit" class="btn btn-primary" [hidden]="dialogState !== 1" + (click)="navigateUploadScreen()">Next</button> + <button type="submit" class="btn btn-primary" [hidden]="dialogState !== 2" + (click)="navigateSelectTypeUpload()">Back</button> + <button type="submit" class="btn btn-primary" [hidden]="dialogState !== 3" (click)="updateInDB()">Ok</button> + <button type="submit" class="btn btn-primary" [hidden]="dialogState !== 3" + (click)="navigateUploadScreen()">Cancel</button> + <button type="button" class="btn btn-primary" [hidden]="dialogState !== 1" + (click)="activeModal.close('Close')">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.scss b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.scss new file mode 100644 index 00000000..6ed732b7 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.scss @@ -0,0 +1,41 @@ +/*- + * ============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-bulk-upload { + overflow-y: auto; + height: 250px; + }
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.spec.ts b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.spec.ts new file mode 100644 index 00000000..d4006a08 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.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 { BulkUploadRoleComponent } from './bulk-upload-role.component'; + +describe('BulkUploadRoleComponent', () => { + let component: BulkUploadRoleComponent; + let fixture: ComponentFixture<BulkUploadRoleComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BulkUploadRoleComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BulkUploadRoleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.ts b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.ts new file mode 100644 index 00000000..698889b7 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/bulk-upload-role/bulk-upload-role.component.ts @@ -0,0 +1,978 @@ +/*- + * ============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, Output, EventEmitter, Input } from '@angular/core'; +import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { RoleService, FunctionalMenuService } from 'src/app/shared/services'; +import { MatTableDataSource } from '@angular/material'; + +@Component({ + selector: 'app-bulk-upload-role', + templateUrl: './bulk-upload-role.component.html', + styleUrls: ['./bulk-upload-role.component.scss'] +}) +export class BulkUploadRoleComponent implements OnInit { + + + @Input() title: string; + closeResult: string; + @Input() appId: string; + @Input() dialogState: number; + ngRepeatBulkUploadOptions = [ + { id: '1', title: 'Functions', value: 'functions' }, + { id: '2', title: 'Roles', value: 'roles' }, + { id: '3', title: 'Role Functions', value: 'roleFunctions' }, + { id: '4', title: 'Global Role Functions', value: 'globalRoleFunctions' } + ]; + selectedUploadDropdown: any; + uploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name"; + uploadCheck: boolean; + isProcessing: boolean; + conformMsg: string; + progressMsg: string; + uploadFile: any; + // Roles fetched from Role service + appRoleFuncsResult = []; + // Functions fetched from Role service + appFunctionsResult = []; + // Global roles fetched from Role service + appGlobalRolesResult = []; + changeUploadTypeInstruction(typeInstrc) { + switch (typeInstrc) { + case 'functions': + this.uploadTypeInstruction = "Function Type, Function Instance, Function Action, Function Name"; + break; + case 'roles': + this.uploadTypeInstruction = "Role Name, Priority (Optional)"; + break; + case 'roleFunctions': + this.uploadTypeInstruction = "Role Name, Function Type, Function Instance, Function Action, Function Name"; + break; + default: + this.uploadTypeInstruction = "Global Role Name, Function Type, Function Instance, Function Action, Function Name"; + } + }; + + fileModel: {}; + step1: boolean; + fileSelected: boolean; + isProcessedRecords: boolean; + displayedFunctionColumns: string[] = ['line', 'type', 'instance', 'action', 'name', 'status']; + uploadFunctionsDataSource = new MatTableDataSource(this.uploadFile); + displayedRoleColumns: string[] = ['line', 'name', 'priority', 'status']; + uploadRolesDataSource = new MatTableDataSource(this.uploadFile); + displayedRoleFunctionColumns: string[] = ['line', 'role', 'type', 'instance', 'action', 'name', 'status']; + uploadRoleFunctionsDataSource = new MatTableDataSource(this.uploadFile); + displayedGlobalRoleFunctionColumns: string[] = ['line', 'role', 'type', 'instance', 'action', 'name', 'status']; + uploadGlobalRoleFunctionsDataSource = new MatTableDataSource(this.uploadFile); + + constructor(public activeModal: NgbActiveModal, public ngbModal: NgbModal, private roleService: RoleService, private functionalMenuService: FunctionalMenuService) { } + + ngOnInit() { + this.selectedUploadDropdown = this.ngRepeatBulkUploadOptions[0]; + this.fileModel = {}; + // Enable modal controls + this.step1 = true; + + this.fileSelected = false; + + this.isProcessedRecords = false; + } + + navigateUploadScreen() { + if (this.selectedUploadDropdown.value === 'functions') { + this.title = 'Bulk Upload Functions Confirmation'; + } else if (this.selectedUploadDropdown.value === 'roles') { + this.title = 'Bulk Upload Roles Confirmation'; + } else if (this.selectedUploadDropdown.value === 'roleFunctions') { + this.title = 'Bulk Upload Role-Functions Confirmation'; + } else { + this.title = 'Bulk Upload Global-Role-Functions Confirmation'; + } + this.dialogState = 2; + } + + navigateSelectTypeUpload() { + this.title = 'Bulk Upload Role-Function'; + this.dialogState = 1; + } + + updateInDB() { + if (this.selectedUploadDropdown.value === 'functions') { + this.updateFunctionsInDB(); + } else if (this.selectedUploadDropdown.value === 'roles') { + this.updateRolesInDB(); + } else if (this.selectedUploadDropdown.value === 'roleFunctions') { + this.updateRoleFunctionsInDB(); + } else { + this.updateGlobalRoleFunctionsInDB(); + } + } + // Answers a function that compares properties with the specified name. + getSortOrder = (prop, foldCase) => { + return function (a, b) { + let aProp = foldCase ? a[prop].toLowerCase() : a[prop]; + let bProp = foldCase ? b[prop].toLowerCase() : b[prop]; + if (aProp > bProp) + return 1; + else if (aProp < bProp) + return -1; + else + return 0; + } + } + + onFileLoad(fileLoadedEvent) { + const textFromFileLoaded = fileLoadedEvent.target.result; + let lines = textFromFileLoaded.split('\n'); + var result = []; + var len, i, line, o; + switch (this.selectedUploadDropdown.value) { + case 'functions': + for (len = lines.length, i = 1; i <= len; ++i) { + line = lines[i - 1].trim(); + + if (line.length == 0) { + // console.log("Skipping blank line"); + result.push({ + line: i, + type: '', + instance: '', + action: '', + name: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length !== 4) { + // other lengths not valid for upload + result.push({ + line: i, + type: o[0], + instance: o[1], + action: o[2], + name: '', + status: 'Failed to find 4 comma-separated values' + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + type: o[0], + instance: o[1], + action: o[2], + name: o[3] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'type') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'instance') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'action') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'name') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].trim() == '' || o[1].trim() == '' || o[2].trim() == '' || o[3].trim() == '') { + // defend against line with only a + // single comma etc. + entry['status'] = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + }// for + break; + case 'roles': + for (len = lines.length, i = 1; i <= len; ++i) { + line = lines[i - 1].trim(); + if (line.length == 0) { + // console.log("Skipping blank line"); + result.push({ + line: i, + role: '', + priority: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length === 0 && line.length !== 0) { + // other lengths not valid for upload + result.push({ + line: i, + role: o[0], + priority: null + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + role: o[0], + priority: o[1] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'role') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + if (o[0].toLowerCase() === 'priority') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].trim() == '') { + // defend against line with only a + // single comma etc. + entry['status'] = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + } + break; + case 'roleFunctions': + case 'globalRoleFunctions': + for (len = lines.length, i = 1; i <= len; ++i) { + line = lines[i - 1].trim(); + if (line.length == 0) { + // console.log("Skipping blank line"); + result.push({ + line: i, + role: '', + type: '', + instance: '', + action: '', + name: '', + status: 'Blank line' + }); + continue; + } + o = line.split(','); + if (o.length !== 5) { + // other lengths not valid for upload + result.push({ + line: i, + role: o[0], + type: o[1], + instance: o[2], + action: o[3], + name: '', + status: 'Failed to find 4 comma-separated values' + }); + } + else { + // console.log("Valid line: ", val); + let entry = { + line: i, + role: o[0], + type: o[1], + instance: o[2], + action: o[3], + name: o[4] + // leave status undefined, this + // could be valid. + }; + if (o[0].toLowerCase() === 'role') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } else if (o[0].toLowerCase() === 'type') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'instance') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'action') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].toLowerCase() === 'name') { + // not valid for upload, so set status + entry['status'] = 'Header'; + } + else if (o[0].trim() == '' || o[1].trim() == '' || o[2].trim() == '' || o[3].trim() == '' || o[4].trim() == '') { + // defend against line with only a + // single comma etc. + entry['status'] = 'Failed to find non-empty values'; + } + result.push(entry); + } // len 2 + } + break; + default: + result = []; + break; + } + return result; + } + + + onFileSelect(input: HTMLInputElement) { + var validExts = new Array(".csv", ".txt"); + var fileExt = input.value; + fileExt = fileExt.substring(fileExt.lastIndexOf('.')); + if (validExts.indexOf(fileExt) < 0) { + const modalFileErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalFileErrorRef.componentInstance.title = 'Confirmation'; + modalFileErrorRef.componentInstance.message = 'Invalid file selected, valid files are of ' + + validExts.toString() + ' types.' + this.uploadCheck = false; + return false; + } + else { + const files = input.files; + this.isProcessing = true; + this.conformMsg = ''; + this.isProcessedRecords = true; + this.progressMsg = 'Reading upload file..'; + if (files && files.length) { + this.uploadCheck = true; + const fileToRead = files[0]; + const fileReader = new FileReader(); + fileReader.readAsText(fileToRead, "UTF-8"); + fileReader.onloadend = (e) => { + this.uploadFile = this.onFileLoad(e); + if (this.selectedUploadDropdown.value === 'roles') { + // if (debug){ + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + this.uploadFile.length); + // } + this.progressMsg = 'Fetching & validating application roles...'; + // fetch app roles + this.roleService.getRoles(this.appId).toPromise().then((appRoles: any) => { + // if (debug){ + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + // } + let availableRolesList = JSON.parse(appRoles.data); + this.appRoleFuncsResult = availableRolesList.availableRoles; + this.evalAppRolesCheckResults(); + // Re sort by line for the confirmation dialog + this.uploadFile.sort(this.getSortOrder('line', false)); + // We're done, confirm box may show the table + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + this.progressMsg = 'Done.'; + this.isProcessing = false; + this.isProcessedRecords = false; + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + this.isProcessing = false; + this.isProcessedRecords = false; + }); + + this.uploadRolesDataSource = new MatTableDataSource(this.uploadFile); + this.dialogState = 3; + } else if (this.selectedUploadDropdown.value === 'roleFunctions') { + // if (debug) { + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + this.uploadFile.length); + // } + this.progressMsg = 'Fetching & validating application role functions...'; + //fetch app functions + this.roleService.getRoleFunctionList(this.appId).toPromise().then((appFunctions: any) => { + // if (debug) + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + this.appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + // fetch app roles + this.roleService.getRoles(this.appId).toPromise().then((appRoles: any) => { + // if (debug) { + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + // } + let availableRolesList = JSON.parse(appRoles.data); + this.appRoleFuncsResult = availableRolesList.availableRoles; + this.evalAppRoleFuncsCheckResults(this.selectedUploadDropdown.value); + // Re sort by line for the confirmation dialog + this.uploadFile.sort(this.getSortOrder('line', false)); + // We're done, confirm box may show the table + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + this.progressMsg = 'Done.'; + this.isProcessing = false; + this.isProcessedRecords = false; + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + this.isProcessing = false; + this.isProcessedRecords = false; + }); + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + this.isProcessing = false; + } + ); + this.uploadRoleFunctionsDataSource = new MatTableDataSource(this.uploadFile); + this.dialogState = 3; + } else if (this.selectedUploadDropdown.value === 'functions') { + // if (debug) { + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + this.uploadFile.length); + // } + this.progressMsg = 'Fetching & validating the application functions...'; + // fetch app functions + this.roleService.getRoleFunctionList(this.appId).toPromise().then((appFunctions: any) => { + // if (debug) + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + this.appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + this.verifyFunctions(); + this.evalAppFunctionsCheckResults(); + // Re sort by line for the confirmation dialog + this.uploadFile.sort(this.getSortOrder('line', false)); + // We're done, confirm box may show the table + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + this.progressMsg = 'Done.'; + this.isProcessing = false; + this.isProcessedRecords = false; + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + this.isProcessing = false; + this.isProcessedRecords = false; + } + ); + this.uploadFunctionsDataSource = new MatTableDataSource(this.uploadFile); + this.dialogState = 3; + } else if (this.selectedUploadDropdown.value === 'globalRoleFunctions') { + // if (debug) { + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile onload: data length is ' + this.uploadFile.length); + // } + this.progressMsg = 'Fetching application global role functions...'; + //fetch app functions + this.roleService.getRoleFunctionList(this.appId).toPromise().then((appFunctions: any) => { + // if (debug) + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoleFunctionList returned " + JSON.stringify(appFunctions.data)); + let availableRoleFunctionsList = JSON.parse(appFunctions.data); + this.appFunctionsResult = availableRoleFunctionsList.availableRoleFunctions; + // fetch app roles + this.roleService.getRoles(this.appId).toPromise().then((appRoles: any) => { + // if (debug) { + // $log.debug("BulkRoleAndFunctionsModalCtrl::readValidateFile: getRoles returned " + JSON.stringify(appFunctions.data)); + // } + let availableRolesList = JSON.parse(appRoles.data); + this.appRoleFuncsResult = availableRolesList.availableRoles; + this.appRoleFuncsResult.forEach((appRole) => { + if (appRole.name.toLowerCase().startsWith("global_")) { + this.appGlobalRolesResult.push(appRole); + } + }); + this.evalAppRoleFuncsCheckResults(this.selectedUploadDropdown.value); + // Re sort by line for the confirmation dialog + this.uploadFile.sort(this.getSortOrder('line', false)); + // We're done, confirm box may show the table + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::readValidateFile inner-then ends'); + this.progressMsg = 'Done.'; + this.isProcessing = false; + this.isProcessedRecords = false; + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app roles info'); + this.isProcessing = false; + this.isProcessedRecords = false; + }); + this.uploadGlobalRoleFunctionsDataSource = new MatTableDataSource(this.uploadFile); + this.dialogState = 3; + }, (error) => { + // $log.error('BulkUserModalCtrl::readValidateFile: failed retrieving app functions info'); + this.isProcessing = false; + } + ); + } + } + } + } + } + + + /** + * Evaluates the result set returned by the role service. + * Sets an uploadFile array element status if a functions is not + * defined. Reads and writes scope variable uploadFile. Reads + * closure variable appFunctionsResult. + */ + verifyFunctions() { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: appFunctions is ' + JSON.stringify(appFunctionsResult)); + // check functions in upload file against defined app functions + this.uploadFile.forEach((uploadRow) => { + // skip rows that already have a defined status: headers etc. + if (uploadRow.status) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: skip row ' + uploadRow.line); + return; + } + for (var i = 0; i < this.appFunctionsResult.length; i++) { + if (uploadRow.type.toUpperCase() === this.appFunctionsResult[i].type.toUpperCase() + && uploadRow.instance.toUpperCase() === this.appFunctionsResult[i].code.toUpperCase() + && uploadRow.action.toUpperCase() === this.appFunctionsResult[i].action.toUpperCase()) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::verifyFunctions: match on function ' + uploadRow.type, + // uploadRow.instance, uploadRow.type, uploadRow.type); + break; + } + } + }); // foreach + }; // verifyFunctions + + /** + * Evaluates the result set of existing functions returned by + * the Roleservice and list of functions found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appFunctionsResult. + */ + evalAppFunctionsCheckResults() { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: uploadFile length is ' + $scope.uploadFile.length); + this.uploadFile.forEach((uploadRow) => { + if (uploadRow.status) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-functions + // array + let isFunctionExist = false; + this.appFunctionsResult.forEach((exixtingFuncObj) => { + if (uploadRow.type.toUpperCase() === exixtingFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === exixtingFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === exixtingFuncObj.action.toUpperCase()) { + uploadRow.status = 'Function exits!'; + uploadRow.isCreate = false; + isFunctionExist = true; + } + }); // for each result + if (!isFunctionExist) { + if (/[^a-zA-Z0-9\-\.\_]/.test(uploadRow.type) + || (uploadRow.action !== '*' + && /[^a-zA-Z0-9\-\.\_]/.test(uploadRow.action)) + || /[^a-zA-Z0-9\-\:\_\./*]/.test(uploadRow.instance) + || /[^a-zA-Z0-9\-\_ \.]/.test(uploadRow.name)) { + uploadRow.status = 'Invalid function'; + uploadRow.isCreate = false; + } else { + // if (debug){ + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppFunctionsCheckResults: new function ' + // + uploadRow); + // } + // After much back-and-forth I decided a clear indicator is better than blank in the table status column. + uploadRow.status = 'Create'; + uploadRow.isCreate = true; + } + } + }); // for each row + }; // evalAppFunctionsCheckResults + + + /** + * Evaluates the result set of existing roles returned by + * the Roleservice and list of roles found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appRolesResult. + */ + evalAppRolesCheckResults() { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: uploadFile length is ' + this.uploadFile.length); + this.uploadFile.forEach((uploadRow) => { + if (uploadRow.status) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-roles + // array + let isRoleExist = false; + this.appRoleFuncsResult.forEach((existingRoleObj) => { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + uploadRow.status = 'Role exits!'; + uploadRow.isCreate = false; + isRoleExist = true; + } + }); // for each result + if (!isRoleExist) { + if (/[^a-zA-Z0-9\-\_ \.\/]/.test(uploadRow.role) || + uploadRow.role.toLowerCase().startsWith("global_")) { + uploadRow.status = 'Invalid role!'; + uploadRow.isCreate = false; + } else { + // if (debug){ + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRolesCheckResults: new function ' + // + uploadRow); + // } + // After much back-and-forth I decided a clear indicator is better than blank in the table status column. + uploadRow.status = 'Create'; + uploadRow.isCreate = true; + } + } + }); // for each row + }; // evalAppRolesCheckResults + + /** + * Evaluates the result set of existing roles returned by + * the Roleservice and list of roles found in the upload file. + * Reads and writes scope variable uploadFile. + * Reads closure variable appRolesResult. + */ + evalAppRoleFuncsCheckResults(typeUpload) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: uploadFile length is ' + this.uploadFile.length); + this.uploadFile.forEach((uploadRow) => { + if (uploadRow.status) { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::evalAppRoleFuncsCheckResults: skip row ' + uploadRow.line); + return; + } + // Search for the match in the app-functions array + let isValidFunc = false; + this.appFunctionsResult.forEach((existingFuncObj) => { + if (uploadRow.type.toUpperCase() === existingFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingFuncObj.action.toUpperCase() + && uploadRow.name.toUpperCase() === existingFuncObj.name.toUpperCase()) { + isValidFunc = true; + } + }); + + let isValidRole = false; + let isRoleFuncExist = false; + if (typeUpload === 'globalRoleFunctions') { + // Search for the match in the app-role array + this.appGlobalRolesResult.forEach((existingRoleObj) => { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + isValidRole = true; + if (isValidFunc) { + existingRoleObj.roleFunctions.forEach((existingRoleFuncObj) => { + if (uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()) { + isRoleFuncExist = true; + } + }); + } + } + }); // for each result + } else { + // Search for the match in the app-role array + this.appRoleFuncsResult.forEach((existingRoleObj) => { + if (uploadRow.role.toUpperCase() === existingRoleObj.name.toUpperCase()) { + isValidRole = true; + if (isValidFunc) { + existingRoleObj.roleFunctions.forEach((existingRoleFuncObj) => { + if (uploadRow.type.toUpperCase() === existingRoleFuncObj.type.toUpperCase() + && uploadRow.instance.toUpperCase() === existingRoleFuncObj.code.toUpperCase() + && uploadRow.action.toUpperCase() === existingRoleFuncObj.action.toUpperCase()) { + isRoleFuncExist = true; + } + }); + } + } + }); // for each result + } + + uploadRow.isCreate = false; + if (typeUpload === 'globalRoleFunctions' && (!isValidRole || !isValidFunc)) { + uploadRow.status = 'Invalid global role function!'; + } else if (typeUpload !== 'globalRoleFunctions' && (!isValidRole || !isValidFunc)) { + uploadRow.status = 'Invalid role function!'; + } else if (typeUpload === 'globalRoleFunctions' && !isRoleFuncExist) { + uploadRow.status = 'Add global role function!'; + uploadRow.isCreate = true; + } else if (typeUpload !== 'globalRoleFunctions' && !isRoleFuncExist) { + uploadRow.status = 'Add role function!'; + uploadRow.isCreate = true; + } else if (typeUpload === 'globalRoleFunctions') { + uploadRow.status = 'Global role function exists!'; + } else { + uploadRow.status = 'Role function exists!'; + } + + }); // for each row + }; // evalAppRolesCheckResults + + + /** + * Sends requests to Portal BE requesting application functions assignment. + * That endpoint handles creation of the application functions in the + * external auth system if necessary. Reads closure variable appFunctionsResult. + * Invoked by the Next button on the confirmation dialog. + */ + updateFunctionsInDB() { + this.isProcessing = true; + this.conformMsg = ''; + this.isProcessedRecords = true; + this.progressMsg = 'Sending requests to application..'; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberFunctionsSucceeded = 0; + let promises = []; + this.uploadFile.forEach((appFuncPostData) => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: appFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateFunctionsFinalPostData = { + type: appFuncPostData.type, + code: appFuncPostData.instance, + action: appFuncPostData.action, + name: appFuncPostData.name + }; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updateFunctionsFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if (appFuncPostData.isCreate) { + updatePromise = this.functionalMenuService.saveBulkFunction(this.appId, updateFunctionsFinalPostData).toPromise().then(res => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberFunctionsSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + // $log.error('BulkRoleAndFunctionsModalCtrl::updateFunctionsInDB failed: ', err); + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to update the application functions.' + 'Error: ' + err.status; + }).finally(() => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + Promise.all(promises).then(() => { + this.conformMsg = 'Processed ' + numberFunctionsSucceeded + ' records.'; + this.isProcessing = false; + this.isProcessedRecords = true; + this.uploadFile = []; + this.dialogState = 2; + }); + }; // updateFunctionsInDB + + /** + * Sends requests to Portal BE requesting application functions assignment. +* That endpoint handles creation of the application role in the +* external auth system if necessary. Reads closure variable appRoleFuncResult. +* Invoked by the Next button on the confirmation dialog. +*/ + updateRolesInDB() { + this.isProcessing = true; + this.conformMsg = ''; + this.isProcessedRecords = true; + this.progressMsg = 'Sending requests to application..'; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: request length is ' + appUserRolesRequest.length); + var numberRolesSucceeded = 0; + let promises = []; + this.uploadFile.forEach((appRolePostData) => { + let priority = parseInt(appRolePostData.priority); + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: appRolePostData is ' + JSON.stringify(appFuncPostData)); + let uplaodRolePostData = {}; + if (isNaN(priority)) { + uplaodRolePostData = { + name: appRolePostData.role, + active: true, + } + } else { + uplaodRolePostData = { + name: appRolePostData.role, + priority: appRolePostData.priority, + active: true, + } + } + var postData = { + role: uplaodRolePostData, + roleFunctions: [], + childRoles: [] + } + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: uplaodRoleFinalPostData is ' + JSON.stringify(uplaodRoleFinalPostData)); + let updatePromise = {}; + if (appRolePostData.isCreate) { + updatePromise = this.functionalMenuService.saveBulkRole(this.appId, JSON.stringify(postData)).toPromise().then(res => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRolesInDB: updated successfully: ' + JSON.stringify(res)); + numberRolesSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + // $log.error('BulkRoleAndFunctionsModalCtrl::updateRolesInDB failed: ', err); + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to update the application role. ' + + 'Error: ' + err.status; + }).finally(() => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + Promise.all(promises).then(() => { + if (numberRolesSucceeded == 0) { + this.conformMsg = 'Processed ' + numberRolesSucceeded + ' records'; + } else { + this.conformMsg = 'Processed ' + numberRolesSucceeded + ' records. Please sync roles to reflect in portal'; + } this.isProcessing = false; + this.isProcessedRecords = true; + this.uploadFile = []; + this.dialogState = 2; + }); + }; // updateRolesInDB + + /** + * Sends requests to Portal BE requesting role function assignment. + * That endpoint handles adding role function in the external auth system + * if necessary.Invoked by the Next button on the confirmation dialog. + */ + updateRoleFunctionsInDB() { + this.isProcessing = true; + this.conformMsg = ''; + this.isProcessedRecords = true; + this.progressMsg = 'Sending requests to application..'; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberRoleFunctionSucceeded = 0; + let promises = []; + this.uploadFile.forEach((appRoleFuncPostData) => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateRoleFunctionFinalPostData = { + roleName: appRoleFuncPostData.role, + type: appRoleFuncPostData.type, + instance: appRoleFuncPostData.instance, + action: appRoleFuncPostData.action, + name: appRoleFuncPostData.name, + isGlobalRolePartnerFunc: false + }; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if (appRoleFuncPostData.isCreate) { + updatePromise = this.functionalMenuService.updateBulkRoleFunction(this.appId, updateRoleFunctionFinalPostData).toPromise().then(res => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberRoleFunctionSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + // $log.error('BulkRoleAndFunctionsModalCtrl::updateRoleFunctionsInDB failed: ', err); + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to update the application role function. ' + + 'Error: ' + err.status; + }).finally(() => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + Promise.all(promises).then(() => { + if (numberRoleFunctionSucceeded == 0) { + this.conformMsg = 'Processed ' + numberRoleFunctionSucceeded + ' records'; + } else { + this.conformMsg = 'Processed ' + numberRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal'; + } this.isProcessing = false; + this.isProcessedRecords = true; + this.uploadFile = []; + this.dialogState = 2; + }); + }; // updateRoleFunctionsInDB + + /** + * Sends requests to Portal requesting global role functions assignment. + * That endpoint handles updating global role functions in the external auth system + * if necessary. Invoked by the Next button on the confirmation dialog. + */ + updateGlobalRoleFunctionsInDB() { + this.isProcessing = true; + this.conformMsg = ''; + this.isProcessedRecords = true; + this.progressMsg = 'Sending requests to application..'; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: request length is ' + appUserRolesRequest.length); + var numberGlobalRoleFunctionSucceeded = 0; + let promises = []; + this.uploadFile.forEach((appRoleFuncPostData) => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: appRoleFuncPostData is ' + JSON.stringify(appFuncPostData)); + let updateGlobalRoleFunctionFinalPostData = { + roleName: appRoleFuncPostData.role, + type: appRoleFuncPostData.type, + instance: appRoleFuncPostData.instance, + action: appRoleFuncPostData.action, + name: appRoleFuncPostData.name, + isGlobalRolePartnerFunc: true + }; + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updateRoleFunctionFinalPostData is ' + JSON.stringify(updateFunctionsFinalPostData)); + let updatePromise = {}; + if (appRoleFuncPostData.isCreate) { + updatePromise = this.functionalMenuService.updateBulkRoleFunction(this.appId, updateGlobalRoleFunctionFinalPostData).toPromise().then(res => { + // if (debug) + // $log.debug('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB: updated successfully: ' + JSON.stringify(res)); + numberGlobalRoleFunctionSucceeded++; + }).catch(err => { + // What to do if one of many fails?? + // $log.error('BulkRoleAndFunctionsModalCtrl::updateGlobalRoleFunctionsInDB failed: ', err); + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to update the global role partner function. ' + + 'Error: ' + err.status; + }).finally(() => { + }); + } + promises.push(updatePromise); + }); // for each + + // Run all the promises + Promise.all(promises).then(() => { + if (numberGlobalRoleFunctionSucceeded == 0) { + this.conformMsg = 'Processed ' + numberGlobalRoleFunctionSucceeded + ' records'; + } else { + this.conformMsg = 'Processed ' + numberGlobalRoleFunctionSucceeded + ' records. Please sync roles to reflect in portal'; + } + this.isProcessing = false; + this.isProcessedRecords = true; + this.uploadFile = []; + this.dialogState = 2; + }); + }; // updateGlobalRoleFunctionsInDB + +} diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.html b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.html new file mode 100644 index 00000000..be7dc2a1 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.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="modal-header"> + <h4 class="modal-title">{{title}}</h4> + <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross')"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <span class="onap-spinner" *ngIf="showSpinner"></span> + <form> + <fieldset class="form-group"> + <div class="row"> + <legend class="col-form-label col-sm-2 pt-0">Type</legend> + <div class="col-sm-10"> + <div class="form-check"> + <mat-radio-group aria-labelledby="type-radio-group-label" class="type-radio-group" + [(ngModel)]="selectedType" name="selectedType"> + <mat-radio-button class="type-radio-button" [disabled]="editDisable" *ngFor="let type of typeOptions" [value]="type"> + {{type}} + </mat-radio-button> + </mat-radio-group> + </div> + </div> + </div> + </fieldset> + <div *ngIf="selectedType === 'other'" class="form-group row"> + <label for="inputOtherType" class="col-sm-2 col-form-label"></label> + <div class="col-sm-10"> + <input type="text" class="form-control" [disabled]="editDisable" [(ngModel)]="otherTypeValue" name="type2" id="inputOtherType" + placeholder="Type"> + </div> + </div> + <div class="form-group row"> + <label for="inputInstance" class="col-sm-2 col-form-label">Instance</label> + <div class="col-sm-10"> + <input type="text" class="form-control" [disabled]="editDisable" [(ngModel)]="roleFunction.code" name="code" id="inputInstance" + placeholder="Instance"> + </div> + </div> + <div class="form-group row"> + <label for="inputAction" class="col-sm-2 col-form-label">Action</label> + <div class="col-sm-10"> + <input type="text" class="form-control" [disabled]="editDisable" [(ngModel)]="roleFunction.action" name="action" id="inputAction" + placeholder="Action"> + </div> + </div> + <div class="form-group row"> + <label for="inputName" class="col-sm-2 col-form-label">Name</label> + <div class="col-sm-10"> + <input type="text" class="form-control" [(ngModel)]="roleFunction.name" name="name" id="inputName" + placeholder="Name"> + </div> + </div> + </form> + </div> + <div class="modal-footer"> + <button type="submit" class="btn btn-primary" + [disabled]="(selectedType === 'other' && otherTypeValue.length === 0 ) || (roleFunction.code.length === 0 || roleFunction.action.length === 0 || roleFunction.name.length === 0)" + (click)="saveRoleFunction()">Save</button> + <button type="button" class="btn btn-primary" (click)="activeModal.close('Close')">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.scss b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.scss new file mode 100644 index 00000000..fff036cd --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.scss @@ -0,0 +1,40 @@ +/*- + * ============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============================================ + * + * + */ +.onap-spinner{ + z-index: 9999; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.spec.ts b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.spec.ts new file mode 100644 index 00000000..2c5ef631 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.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 { RoleFunctionModalComponent } from './role-function-modal.component'; + +describe('RoleFunctionModalComponent', () => { + let component: RoleFunctionModalComponent; + let fixture: ComponentFixture<RoleFunctionModalComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RoleFunctionModalComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RoleFunctionModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.ts b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.ts new file mode 100644 index 00000000..d54cd02c --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-function-modal/role-function-modal.component.ts @@ -0,0 +1,165 @@ +/*- + * ============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 { RoleFunction, Role } from 'src/app/shared/model'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { environment } from 'src/environments/environment'; +import { HttpClient } from '@angular/common/http'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; + +@Component({ + selector: 'app-role-function-modal', + templateUrl: './role-function-modal.component.html', + styleUrls: ['./role-function-modal.component.scss'] +}) +export class RoleFunctionModalComponent implements OnInit { + + @Input() title: string; + @Input() appId: any; + @Input() dialogState: number; + @Input() currentRoleFunctions: any; + @Input() editRoleFunction: RoleFunction; + @Output() passBackRoleFunctionPopup: EventEmitter<any> = new EventEmitter(); + roleFunction: RoleFunction; + otherTypeValue: string; + typeOptions: string[] = ['menu', 'url', 'other']; + api = environment.api; + isEditing: any; + editDisable: boolean; + showSpinner: boolean; + selectedType: string; + createOrUpdate: string; + constructor(public activeModal: NgbActiveModal, public ngbModal: NgbModal, public http: HttpClient) { } + + ngOnInit() { + this.createOrUpdate = 'create'; + this.selectedType = 'menu'; + this.roleFunction = new RoleFunction(this.selectedType, '', '*', ''); + this.otherTypeValue = ''; + if (this.editRoleFunction) { + this.createOrUpdate = 'update'; + this.editDisable = true; + this.selectedType = this.editRoleFunction.type; + if (this.editRoleFunction.type !== 'menu' && this.editRoleFunction.type !== 'url') { + this.selectedType = 'other'; + this.otherTypeValue = this.editRoleFunction.type; + } + this.roleFunction = new RoleFunction(this.editRoleFunction.type, this.editRoleFunction.code, this.editRoleFunction.action, this.editRoleFunction.name); + } + } + + saveRoleFunction() { + if (/[^a-zA-Z0-9\-\.\_]/.test(this.roleFunction.type) && this.selectedType === 'other') { + this.openConfirmationModal('Confirmation', 'Type can only contain alphanumeric characters, dots(.) and underscores(_)'); + return; + } else { + this.roleFunction.type = this.selectedType; + } + if (this.roleFunction.action !== '*' && /[^a-zA-Z0-9\-\.\_]/.test(this.roleFunction.action)) { + this.openConfirmationModal('Confirmation', 'Action can only contain alphanumeric characters, hyphens(-), dots(.) and underscores(_) and single asterisk character(*)'); + return; + } + if (/[^a-zA-Z0-9\-\:\_\./*]/.test(this.roleFunction.code)) { + this.openConfirmationModal('Confirmation', 'Instance can only contain alphanumeric characters, hyphens(-), dots(.), colons(:), forwardSlash(/) , asterisk(*) and underscores(_)'); + return; + } + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = 'You are about to ' + this.createOrUpdate + ' the role function ' + this.roleFunction.name + '. Do you want to continue?'; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') { + this.showSpinner = true; + var uuu = this.api.saveRoleFunction.replace(':appId', this.appId); + var postData = this.roleFunction; + var exists = false, x; + for (x in this.currentRoleFunctions) { + if (this.currentRoleFunctions[x].type == this.roleFunction.type + && this.currentRoleFunctions[x].code == this.roleFunction.code + && this.currentRoleFunctions[x].action == this.roleFunction.action + && this.currentRoleFunctions[x].name == this.roleFunction.name) { + this.openConfirmationModal('Confirmation', "Role Function already exist."); + exists = true; + this.showSpinner = false; + break; + } + if (!this.editDisable) { + if (this.currentRoleFunctions[x].type == this.roleFunction.type + && this.currentRoleFunctions[x].code == this.roleFunction.code + && this.currentRoleFunctions[x].action == this.roleFunction.action + ) { + this.openConfirmationModal('Confirmation', "Please make sure code, type and action is unique. Please create a role function with a different code or type or action to proceed."); + exists = true; + this.showSpinner = false; + break; + } + } + } + if (this.selectedType === 'other') + this.roleFunction.type = this.otherTypeValue; + if (!exists && this.roleFunction.name.trim() != '' && this.roleFunction.code.trim() != '') { + this.http.post(uuu, JSON.stringify(postData)).toPromise().then((res: any) => { + if (res.status == 'OK') { + this.showSpinner = false; + if (this.editRoleFunction) { + this.editRoleFunction.name = this.roleFunction.name; + this.passBackRoleFunctionPopup.emit(this.editRoleFunction); + } else{ + this.passBackRoleFunctionPopup.emit(this.roleFunction); + } + this.openConfirmationModal('Success', res.message); + } else { + this.showSpinner = false; + this.openConfirmationModal('Error', res.message); + } + }); + + } + } + }, (_dismiss) => { + + }) + } + + + openConfirmationModal(_title: string, _message: string) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = _title; + modalInfoRef.componentInstance.message = _message; + } +} diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.html b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.html new file mode 100644 index 00000000..046d0a07 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.html @@ -0,0 +1,113 @@ +<!-- + ============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="onap-main-view-title"> + <h1 class="heading-page">Role Functions</h1> + </div> + <mat-form-field> + <mat-label> Select Application </mat-label> + <mat-select [disabled]='centralizedApps.length === 0' [(ngModel)]="selectedCentralizedApp"> + <mat-option *ngFor="let app of centralizedApps" [value]="app.appId" + (click)="getRoleFunctions(selectedCentralizedApp)"> + {{app.appName}}</mat-option> + </mat-select> + </mat-form-field> + + <button type="button" class="btn btn-primary" [disabled]='centralizedApps.length === 0' + (click)="syncRolesFromExternalAuthSystem()"><i class="icon ion-md-sync"></i> + Sync Role Functions </button> + <button type="button" class="btn btn-primary" [disabled]='centralizedApps.length === 0' + (click)="addRoleFunctionModalPopup()"><i class="icon ion-md-add-circle-outline"></i> + Create </button> + <span class="onap-spinner" *ngIf="showSpinner"></span> + <table mat-table [dataSource]="roleFunctionsDataSource" matSort> + <!-- Type Column --> + <ng-container matColumnDef="type"> + <th id="col1" mat-header-cell *matHeaderCellDef mat-sort-header> Type </th> + <td id="rowheader_t1_{{i}}-type" mat-cell *matCellDef="let element; let i = index;"> {{element.type}} + </td> + </ng-container> + + <!-- Instance Column --> + <ng-container matColumnDef="instance"> + <th id="col2" mat-header-cell *matHeaderCellDef mat-sort-header> Instance </th> + <td id="rowheader_t1_{{i}}-instance" mat-cell *matCellDef="let element; let i=index;"> {{element.code}} + </td> + </ng-container> + + <!-- Action Column --> + <ng-container matColumnDef="action"> + <th id="col3" mat-header-cell *matHeaderCellDef mat-sort-header> Action </th> + <td id="rowheader_t1_{{i}}-action" mat-cell *matCellDef="let element; let i=index;"> {{element.action}} + </td> + </ng-container> + + <!-- Name Column --> + <ng-container matColumnDef="name"> + <th id="col3" mat-header-cell *matHeaderCellDef mat-sort-header> Name </th> + <td id="rowheader_t1_{{i}}-name" mat-cell *matCellDef="let element; let i=index;"> {{element.name}} + </td> + </ng-container> + + <!-- Edit Column --> + <ng-container matColumnDef="edit"> + <th id="col3" mat-header-cell *matHeaderCellDef mat-sort-header> Edit </th> + <td id="rowheader_t1_{{i}}-userId" mat-cell *matCellDef="let element; let i=index;"> + <span class="icon-trash" id="{{i}}-button-edit" (click)="editRoleFunctionModalPopup(element)"> + <i class="icon ion-md-create"></i> + </span> + </td> + </ng-container> + + <!-- Delete Column --> + <ng-container matColumnDef="delete"> + <th id="col4" mat-header-cell *matHeaderCellDef> Delete </th> + <td id="rowheader_t1_{{i}}-delete" mat-cell *matCellDef="let element; let i=index;"> + <span class="icon-trash" id="{{i}}-button-portal-admin-remove" (click)="removeRoleFunction(element)"> + <i class="icon ion-md-trash"></i> + </span> + </td> + </ng-container> + + <tr [hidden]="availableRoleFunctions.length === 0" mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + </table> + <mat-paginator [hidden]="availableRoleFunctions.length === 0" [pageSizeOptions]="[10, 20]" showFirstLastButtons> + </mat-paginator> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.scss b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.scss new file mode 100644 index 00000000..944e9c8c --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.scss @@ -0,0 +1,47 @@ +/*- + * ============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 "../../pages.component"; + +.icon-trash{ + cursor: pointer; + font-size: 20px; +} + +.onap-spinner{ + z-index: 9999; +}
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.spec.ts b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.spec.ts new file mode 100644 index 00000000..ccefb8d2 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-functions.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 { RoleFunctionsComponent } from './role-functions.component'; + +describe('RoleFunctionsComponent', () => { + let component: RoleFunctionsComponent; + let fixture: ComponentFixture<RoleFunctionsComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RoleFunctionsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RoleFunctionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.ts b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.ts new file mode 100644 index 00000000..1b68526d --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role-functions/role-functions.component.ts @@ -0,0 +1,200 @@ +/*- + * ============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 } from '@angular/core'; +import { RoleService, ApplicationsService } from 'src/app/shared/services'; +import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material'; +import { RoleFunctionModalComponent } from './role-function-modal/role-function-modal.component'; +import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { HttpClient } from '@angular/common/http'; +import { environment } from 'src/environments/environment'; + +@Component({ + selector: 'app-role-functions', + templateUrl: './role-functions.component.html', + styleUrls: ['./role-functions.component.scss'] +}) +export class RoleFunctionsComponent implements OnInit { + api = environment.api + centralizedApps: any; + selectedCentralizedApp: any; + availableRoleFunctions: any; + displayedColumns: string[] = ['type', 'instance', 'action', 'name', 'edit', 'delete']; + roleFunctionsDataSource = new MatTableDataSource(this.availableRoleFunctions); + @ViewChild(MatSort) sort: MatSort; + @ViewChild(MatPaginator) paginator: MatPaginator; + showSpinner: boolean; + + constructor(public ngbModal: NgbModal,private roleService: RoleService, private applicationsService: ApplicationsService, public http: HttpClient) {} + + ngOnInit() { + this.availableRoleFunctions = []; + this.centralizedApps = []; + this.getCentralizedApps(sessionStorage.userId); + } + + syncRolesFromExternalAuthSystem() { + this.applicationsService.syncRolesEcompFromExtAuthSystem(this.selectedCentralizedApp).toPromise().then((res: any) => { + if (res.status == 'OK') { + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Success'; + modalInfoRef.componentInstance.message = 'Sync role functions completed successfully!'; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') + this.getRoleFunctions(this.selectedCentralizedApp); + }, (result) => { + + }) + } else { + this.openConfirmationModal('Error', 'Sync failed ' + res.message); + } + }).catch(err => { + this.openConfirmationModal('Error', 'Sync failed' + err); + }); + }; + + + // getCentalizedApps + getCentralizedApps(userId) { + this.roleService.getCentralizedApps(userId).toPromise().then((res: any) => { + if (res.length > 0) { + this.centralizedApps = res; + this.selectedCentralizedApp = this.centralizedApps[0].appId; + this.getRoleFunctions(this.centralizedApps[0].appId); + } + }).catch(err => { + // $log.error('RoleListCtrl::centralizedApps retrieval error: ', err); + }).finally(() => { + // this.isLoadingTable = false; + }); + } + + getRoleFunctions(id) { + this.showSpinner = true; + this.roleService.getRoleFunctionList(id).subscribe((data: any) => { + this.showSpinner = false; + var j = data; + var roleFunctions = JSON.parse(j.data); + this.availableRoleFunctions = roleFunctions.availableRoleFunctions; + this.roleFunctionsDataSource = new MatTableDataSource(this.availableRoleFunctions); + this.roleFunctionsDataSource.sort = this.sort; + this.roleFunctionsDataSource.paginator = this.paginator; + }, (error) => { + this.showSpinner = false; + this.openConfirmationModal('Error', 'Failed to get role functions. Please try again!' + error.message); + }) + }; + + addRoleFunctionModalPopup(){ + const modalInfoRef = this.ngbModal.open(RoleFunctionModalComponent); + modalInfoRef.componentInstance.title = 'Add Role Function'; + modalInfoRef.componentInstance.appId = this.selectedCentralizedApp; + modalInfoRef.componentInstance.currentRoleFunctions = this.availableRoleFunctions; + modalInfoRef.componentInstance.passBackRoleFunctionPopup.subscribe((_result: any) => { + if(_result){ + modalInfoRef.close(); + this.availableRoleFunctions.push(_result); + this.roleFunctionsDataSource = new MatTableDataSource(this.availableRoleFunctions); + this.roleFunctionsDataSource.sort = this.sort; + this.roleFunctionsDataSource.paginator = this.paginator; + } + }, (_reason: any) => { + return; + }); + + } + + editRoleFunctionModalPopup(_element){ + const modalInfoRef = this.ngbModal.open(RoleFunctionModalComponent); + modalInfoRef.componentInstance.title = 'Edit Role Function'; + modalInfoRef.componentInstance.appId = this.selectedCentralizedApp; + modalInfoRef.componentInstance.editRoleFunction = _element; + modalInfoRef.componentInstance.currentRoleFunctions = this.availableRoleFunctions; + modalInfoRef.componentInstance.passBackRoleFunctionPopup.subscribe((_result: any) => { + if(_result){ + modalInfoRef.close(); + this.availableRoleFunctions.splice(this.availableRoleFunctions.indexOf(_element), 1); + this.availableRoleFunctions.push(_result); + this.roleFunctionsDataSource = new MatTableDataSource(this.availableRoleFunctions); + this.roleFunctionsDataSource.sort = this.sort; + this.roleFunctionsDataSource.paginator = this.paginator; + } + }, (_reason: any) => { + return; + }); + } + + removeRoleFunction(_element: any){ + const ngbInfoModal = this.ngbModal.open(InformationModalComponent); + ngbInfoModal.componentInstance.title = 'Confirmation'; + ngbInfoModal.componentInstance.message = 'You are about to delete the role function ' + _element.name + '. Do you want to continue?'; + ngbInfoModal.result.then(_res =>{ + if(_res === 'Ok'){ + this.showSpinner = true; + var uuu = this.api.removeRoleFunction.replace(':appId', this.selectedCentralizedApp); + var postData = _element; + this.http.post(uuu, postData).subscribe((response: any) => { + this.showSpinner = false; + if(response.status == 'OK'){ + this.openConfirmationModal('Success', response.message); + this.availableRoleFunctions.splice(this.availableRoleFunctions.indexOf(_element), 1); + this.roleFunctionsDataSource = new MatTableDataSource(this.availableRoleFunctions); + this.roleFunctionsDataSource.sort = this.sort; + this.roleFunctionsDataSource.paginator = this.paginator; + } else{ + this.showSpinner = false; + this.openConfirmationModal('Error', "Error while deleting: " + response.message); + } + }, (err) => { + this.showSpinner = false; + this.openConfirmationModal('Error', err.message); + }); + } + }, (_reason: any) => { + return; + }); + } + + openConfirmationModal(_title: string, _message: string) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = _title; + modalInfoRef.componentInstance.message = _message; + } + +} diff --git a/portal-FE-common/src/app/pages/role/role.component.html b/portal-FE-common/src/app/pages/role/role.component.html new file mode 100644 index 00000000..9f57aa47 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role.component.html @@ -0,0 +1,115 @@ +<!-- + ============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="onap-main-view-title"> + <h1 class="heading-page">Roles</h1> + </div> + <mat-form-field> + <mat-label> Select Application </mat-label> + <mat-select [disabled]='centralizedApps.length === 0' [(ngModel)]="selectedCentralizedApp"> + <mat-option *ngFor="let app of centralizedApps" [value]="app.appId" + (click)="getRolesForSelectedCentralizedApp(selectedCentralizedApp)"> + {{app.appName}}</mat-option> + </mat-select> + </mat-form-field> + + <button type="button" class="btn btn-primary" [disabled]='centralizedApps.length === 0' + (click)="openBulkUploadRolesAndFunctionsModal()"><i class="icon ion-md-cloud-upload"></i> + Bulk Upload</button> + <button type="button" class="btn btn-primary" [disabled]='centralizedApps.length === 0' [hidden]="!syncRolesApplied" + (click)="syncRolesFromExternalAuthSystem()"><i class="icon ion-md-sync"></i> + Sync Roles </button> + <button type="button" class="btn btn-primary" [disabled]='centralizedApps.length === 0' + (click)="addRoleModalPopup()"><i class="icon ion-md-add-circle-outline"></i> + Create </button> + <span class="onap-spinner" *ngIf="showSpinner"></span> + <table mat-table [dataSource]="roleDataSource" matSort> + <!-- Name Column --> + <ng-container matColumnDef="name"> + <th id="col1" mat-header-cell *matHeaderCellDef mat-sort-header> Name </th> + <td id="rowheader_t1_{{i}}-firstName" mat-cell *matCellDef="let element; let i = index;"> {{element.name}} + </td> + </ng-container> + + <!-- Priority Column --> + <ng-container matColumnDef="priority"> + <th id="col2" mat-header-cell *matHeaderCellDef mat-sort-header> Priority </th> + <td id="rowheader_t1_{{i}}-lastName" mat-cell *matCellDef="let element; let i=index;"> {{element.priority}} + </td> + </ng-container> + + <!-- Active Column --> + <ng-container matColumnDef="active"> + <th id="col3" mat-header-cell *matHeaderCellDef mat-sort-header> Active </th> + <td id="rowheader_t1_{{i}}-userId" mat-cell *matCellDef="let element; let i=index;"> + <mat-slide-toggle + [disabled]="(element.id === 1 || element.id === 999) || ((this.selectedCentralizedApp !== 1) && (element.name.indexOf('global_') !== -1))" + [(ngModel)]="element.active" (change)="toggleRole(element)"></mat-slide-toggle> + </td> + </ng-container> + + <!-- Edit Column --> + <ng-container matColumnDef="edit"> + <th id="col3" mat-header-cell *matHeaderCellDef mat-sort-header> Edit </th> + <td id="rowheader_t1_{{i}}-userId" mat-cell *matCellDef="let element; let i=index;"> + <span class="icon-trash" id="{{i}}-button-edit" (click)="editRoleModalPopup(element)"> + <i class="icon ion-md-create"></i> + </span> + </td> + </ng-container> + + <!-- Delete Column --> + <ng-container matColumnDef="delete"> + <th [hidden]="selectedCentralizedApp === 1" id="col4" mat-header-cell *matHeaderCellDef> Delete </th> + <td [hidden]="selectedCentralizedApp === 1" id="rowheader_t1_{{i}}-applications" mat-cell + *matCellDef="let element; let i=index;"> + <span class="icon-trash" id="{{i}}-button-portal-admin-remove" (click)="removeRole(element)"> + <i class="icon ion-md-trash"></i> + </span> + </td> + </ng-container> + + <tr [hidden]="availableRoles.length === 0" mat-header-row *matHeaderRowDef="displayedColumns"></tr> + <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> + </table> + <mat-paginator [hidden]="availableRoles.length === 0" [pageSizeOptions]="[10, 20]" showFirstLastButtons> + </mat-paginator> + <a id="manage-role" [hidden]="availableRoles.length === 0" [routerLink]="['/roleFunctions']">Manage Role + Functions</a><br><br> +</div>
\ No newline at end of file diff --git a/portal-FE-common/src/app/pages/role/role.component.scss b/portal-FE-common/src/app/pages/role/role.component.scss new file mode 100644 index 00000000..6fc77258 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role.component.scss @@ -0,0 +1,43 @@ +/*- + * ============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 "../pages.component"; + +.icon-trash{ + cursor: pointer; + font-size: 20px; +} diff --git a/portal-FE-common/src/app/pages/role/role.component.spec.ts b/portal-FE-common/src/app/pages/role/role.component.spec.ts new file mode 100644 index 00000000..2dc104d8 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role.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 { RoleComponent } from './role.component'; + +describe('RoleComponent', () => { + let component: RoleComponent; + let fixture: ComponentFixture<RoleComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RoleComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RoleComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-FE-common/src/app/pages/role/role.component.ts b/portal-FE-common/src/app/pages/role/role.component.ts new file mode 100644 index 00000000..0ed39569 --- /dev/null +++ b/portal-FE-common/src/app/pages/role/role.component.ts @@ -0,0 +1,279 @@ +/*- + * ============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 } from '@angular/core'; +import { RoleService, ApplicationsService } from 'src/app/shared/services'; +import { HttpErrorResponse, HttpClient } from '@angular/common/http'; +import { MatTableDataSource, MatSort, MatPaginator } from '@angular/material'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ConfirmationModalComponent } from 'src/app/modals/confirmation-modal/confirmation-modal.component'; +import { InformationModalComponent } from 'src/app/modals/information-modal/information-modal.component'; +import { environment } from 'src/environments/environment'; +import { BulkUploadRoleComponent } from './bulk-upload-role/bulk-upload-role.component'; +import { AddRoleComponent } from './add-role/add-role.component'; + +@Component({ + selector: 'app-role', + templateUrl: './role.component.html', + styleUrls: ['./role.component.scss'] +}) +export class RoleComponent implements OnInit { + + selectedCentralizedApp: any; + centralizedApps: any; + showSpinner: boolean; + availableRoles: any[]; + syncRolesApplied: boolean; + displayedColumns: string[] = ['name', 'priority', 'active', 'edit', 'delete']; + roleDataSource = new MatTableDataSource(this.availableRoles); + @ViewChild(MatSort) sort: MatSort; + @ViewChild(MatPaginator) paginator: MatPaginator; + appName: any; + api = environment.api; + availableRoleFunctions: any; + constructor(private roleService: RoleService, private applicationsService: ApplicationsService, public ngbModal: NgbModal, public http: HttpClient) { } + + ngOnInit() { + this.centralizedApps = []; + this.availableRoles = []; + this.appName = ''; + this.selectedCentralizedApp = ''; + this.getCentralizedApps(sessionStorage.userId); + } + + toggleRole(_element) { + let activeOrInactive = (_element.active) ? 'activate' : 'inactivate'; + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = 'You are about to ' + activeOrInactive + ' the role ' + _element.name + '. Do you want to continue?'; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') { + var uuu = this.api.toggleRole + '/' + this.selectedCentralizedApp + '/' + _element.id; + var postData = { + appId: this.selectedCentralizedApp, + role: _element + }; + this.http.post(uuu, postData).toPromise().then((data: any) => { + if (typeof data === 'object' && data.restcallStatus == 'Success') { + this.availableRoles = data.availableRoles; + this.roleDataSource = new MatTableDataSource(this.availableRoles); + this.roleDataSource.sort = this.sort; + this.roleDataSource.paginator = this.paginator; + // $log.debug('role::availableRoles:'+$scope.availableRoles); + } else { + _element.active = !_element.active; + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Error while saving. ' + data.restCallStatus; + } + + }, (response) => { + // debug.log('response:'+response); + _element.active = !_element.active; + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Error while saving. ' + response.restCallStatus; + }); + } else { + _element.active = !_element.active; + } + + }, (result) => { + + }) + } + + openBulkUploadRolesAndFunctionsModal() { + const modalBulkUploadRole = this.ngbModal.open(BulkUploadRoleComponent); + modalBulkUploadRole.componentInstance.title = 'Bulk Upload Role-Function'; + modalBulkUploadRole.componentInstance.dialogState = 1; + modalBulkUploadRole.componentInstance.appId = this.selectedCentralizedApp; + } + + editRoleModalPopup(_element) { + this.showSpinner = true; + this.roleService.getRole(this.selectedCentralizedApp, _element.id).toPromise().then((data: any) => { + this.showSpinner = false; + var response = JSON.parse(data.data); + var availableRoleFunctions = JSON.parse(response.availableRoleFunctions); + const ngbModalCreateRole = this.ngbModal.open(AddRoleComponent); + ngbModalCreateRole.componentInstance.title = 'Role'; + ngbModalCreateRole.componentInstance.dialogState = 2; + ngbModalCreateRole.componentInstance.availableRole = _element; + ngbModalCreateRole.componentInstance.appRoleFunctions = availableRoleFunctions; + ngbModalCreateRole.componentInstance.appId = this.selectedCentralizedApp; + ngbModalCreateRole.componentInstance.passBackAddRolePopup.subscribe((_result: any) => { + this.showSpinner = true; + this.getAppRoles(_result); + }, (_reason: any) => { + return; + }); + }, (error) => { + this.showSpinner = false; + }); + } + + addRoleModalPopup() { + const ngbModalCreateRole = this.ngbModal.open(AddRoleComponent); + ngbModalCreateRole.componentInstance.title = 'Role'; + ngbModalCreateRole.componentInstance.appId = this.selectedCentralizedApp; + ngbModalCreateRole.componentInstance.passBackAddRolePopup.subscribe((_result: any) => { + this.showSpinner = true; + this.getAppRoles(_result); + }, (_reason: any) => { + return; + }); + + } + + removeRole(_element) { + if ((this.selectedCentralizedApp !== 1) && (_element.name.indexOf('global_') !== -1)) { + const modalInfoRef = this.ngbModal.open(ConfirmationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = 'Global role cannot be deleted.'; + } + else { + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Confirmation'; + modalInfoRef.componentInstance.message = 'You are about to delete the role ' + _element.name + ' . Do you want to continue?'; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') { + var uuu = this.api.removeRole + '/' + this.selectedCentralizedApp + '/' + _element.id; + var postData = { + appId: this.selectedCentralizedApp, + availableRoleId: _element.id + }; + this.http.post(uuu, postData).toPromise().then((data: any) => { + if (typeof data === 'object' && data.restCallStatus == 'Success') { + this.availableRoles = data.availableRoles; + this.roleDataSource = new MatTableDataSource(this.availableRoles); + this.roleDataSource.sort = this.sort; + this.roleDataSource.paginator = this.paginator; + } else { + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to remove role. ' + data.error; + } + }, (_err) => { + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Error while deleting: ' + _err.error; + }) + } + }, (_dismiss) => { + + }); + } + } + + // getCentalizedApps + getCentralizedApps(userId) { + this.showSpinner = true; + this.roleService.getCentralizedApps(userId).toPromise().then((res: any) => { + if (res.length > 0) { + this.centralizedApps = res; + this.selectedCentralizedApp = this.centralizedApps[0].appId; + this.getRolesForSelectedCentralizedApp(this.centralizedApps[0].appId); + } + }).catch(err => { + this.showSpinner = false; + // $log.error('RoleListCtrl::centralizedApps retrieval error: ', err); + }) + } + + syncRolesFromExternalAuthSystem() { + this.applicationsService.syncRolesEcompFromExtAuthSystem(this.selectedCentralizedApp).toPromise().then((res: any) => { + if (res.status == 'OK') { + const modalInfoRef = this.ngbModal.open(InformationModalComponent); + modalInfoRef.componentInstance.title = 'Success'; + modalInfoRef.componentInstance.message = 'Sync operation completed successfully!'; + modalInfoRef.result.then((_res) => { + if (_res === 'Ok') + this.getRolesForSelectedCentralizedApp(this.selectedCentralizedApp); + }, (result) => { + + }) + } else { + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Sync operation failed for ' + this.appName + 'res.message'; + } + }).catch(err => { + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Sync operation failed for ' + this.appName + 'err.message'; + }); + }; + + getRolesForSelectedCentralizedApp(val) { + this.showSpinner = true; + this.availableRoles = []; + this.roleDataSource = new MatTableDataSource(this.availableRoles); + this.applicationsService.getSingleAppInfoById(val).subscribe((res: any) => { + this.appName = res.name; + if (res.centralAuth == true) { + this.syncRolesApplied = true; + } + }); + this.getAppRoles(val); + } + + private getAppRoles(val: any) { + this.roleService.getRoles(val).subscribe((data: any) => { + if (data) { + var j = data; + j = JSON.parse(j.data); + this.availableRoles = j.availableRoles; + this.roleDataSource = new MatTableDataSource(this.availableRoles); + this.roleDataSource.sort = this.sort; + this.roleDataSource.paginator = this.paginator; + this.showSpinner = false; + } + else { + this.showSpinner = false; + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to get ' + this.appName + ' roles. Please try again later!'; + } + }, (error: HttpErrorResponse) => { + this.showSpinner = false; + const modalErrorRef = this.ngbModal.open(ConfirmationModalComponent); + modalErrorRef.componentInstance.title = 'Error'; + modalErrorRef.componentInstance.message = 'Failed to get ' + this.appName + ' roles. Please try again later!'; + }); + } +} |