Skip to content

Commit

Permalink
Merge pull request #127 from bcgov/feature/deseng755
Browse files Browse the repository at this point in the history
feature/deseng755: Fixed permissions page/route pagination and added duplicate filter
  • Loading branch information
jareth-whitney authored Jan 16, 2025
2 parents 4893e37 + 14665ea commit 9d5997d
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 26 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 1.12.1 Jan 15, 2025
* Fixed pagination and added duplicate filtering to permissions page/route. [DESENG-755](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-755)
* Also associated with [DESENG-757](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-757)

### 1.12.0 Jan 9, 2025
* Added the ability to add an external link as if it is an internal file. [DESENG-751](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-751)
* Functionality works in all file views, including file list, file details, file add/edit, comment period view, comment period edit.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "landuseplanning-admin",
"version": "1.12.0",
"version": "1.12.1",
"license": "Apache-2.0",
"scripts": {
"ng": "ng",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<tr *ngFor="let entry of entries"
<tr *ngFor="let entry of entries | paginate: { id: 'table-template-pagination', itemsPerPage: paginationData.pageSize, currentPage: paginationData.currentPage, totalItems: paginationData.totalListItems }"
class="clickable-row">
<td data-label="User" scope="row" class="col-8">{{entry.displayName}}</td>
<td data-label="Access" scope="row" class="col-4">
<mat-checkbox (change)="handlePermissionCheckboxChange($event, entry)"
[checked]=hasProjectPermission(entry)>
[checked]="hasProjectPermission(entry)">
</mat-checkbox>
</td>
</tr>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, Input, ChangeDetectorRef } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { get } from 'lodash';
Expand All @@ -9,6 +9,7 @@ import { UserService } from 'app/services/user.service';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MatSnackBar } from '@angular/material/snack-bar'
import { User } from 'app/models/user'
import { TableParamsObject } from 'app/shared/components/table-template/table-params-object';


@Component({
Expand All @@ -20,17 +21,19 @@ export class PermissionsTableRowsComponent implements OnInit, TableComponent {

@Input() data: TableObject;

public entries: any;
public entries: User[];
public entriesVault;
public targetEmail: any;
private ngUnsubscribe: Subject<boolean> = new Subject<boolean>();
private currentProject;
public paginationData: any;
public tableParams: TableParamsObject = new TableParamsObject();

constructor(
private _changeDetectionRef: ChangeDetectorRef,
private userService: UserService,
private storageService: StorageService,
private snackBar: MatSnackBar,
private router: Router
private router: Router,
) { }

/**
Expand All @@ -39,36 +42,91 @@ export class PermissionsTableRowsComponent implements OnInit, TableComponent {
*
* @return {void}
*/
ngOnInit() {
ngOnInit(): void {
this.currentProject = this.storageService.state.currentProject.data;
this.entries = this.data.data;
this.paginationData = this.data.paginationData;
}

/**
* Opens a new snack bar notification message with a duration of 2 seconds, and executes an action.
*
* @param {string} message A snack bar notification message.
* @param {string} action A snack bar notification action.
* @returns {void}
* @return {void}
*/
public openSnackBar(message: string, action: string): void {
this.snackBar.open(message, action, {
duration: 2000,
});
}

hasProjectPermission(user) {
/**
* Determines if a user has project permission.
*
* @param {User} user The user to check.
* @returns {boolean}
*/
hasProjectPermission(user: User): boolean {
return user.projectPermissions.includes(this.currentProject._id);
}

/**
* Removes duplicate user entries.
*
* @param {User[]} returnedUsers The user list that will be checked for duplicate users.
* @returns {User[]}
*/
removeDuplicateUsers(returnedUsers: User[]): User[] {
const userNames = [];
let validatedUsers = [];
if (Array.isArray(this.entries)) {
returnedUsers.forEach(user => {
if (!userNames.includes(user.displayName)) {
// If no duplicate name is found, validate the user
userNames.push(user.displayName);
validatedUsers.push(user);
} else if (user.projectPermissions.includes(this.currentProject._id)) {
// If a duplicate user is found and they have project permission, replace matching entry if it doesn't have permissions
const matchingUserIndex = validatedUsers.findIndex((usr) => usr.displayName === user.displayName);
validatedUsers[matchingUserIndex] = validatedUsers[matchingUserIndex]?.projectPermissions?.includes(this.currentProject._id) ? validatedUsers[matchingUserIndex] : user;
}
})
}
return validatedUsers;
}

/**
* Load a "page" of users.
*
* @param {number} pageNumber The page number of users to get.
* @return {void}
*/
paginateUsers(pageNumber: number): void {
window.scrollTo(0, 0);
const startIndex = (pageNumber - 1) * this.paginationData.pageSize;
const endIndex = startIndex + this.paginationData.pageSize;
if (endIndex && 0 < this.entriesVault.length) {
this.entries = this.entriesVault.slice(startIndex, endIndex);
}
}

/**
* Handles a permission checkbox change by adding or removing user permissions and reloading results.
*
* @param {MatCheckboxChange} event The event that was captured when the checkbox was changed.
* @param {User} user The user that needs their permissions added or removed.
* @return {void}
*/
handlePermissionCheckboxChange(event: MatCheckboxChange, user: User): void {
if (this.hasProjectPermission(user)) {
this.userService.removeProjectPermission(user, this.currentProject)
.takeUntil(this.ngUnsubscribe)
.subscribe(
(returnedUsers) => {
this.entries = returnedUsers;
this.entriesVault = returnedUsers;
this.entriesVault = this.removeDuplicateUsers(this.entriesVault);
this.paginateUsers(this.paginationData.currentPage);
},
error => {
console.error(error);
Expand All @@ -83,8 +141,9 @@ export class PermissionsTableRowsComponent implements OnInit, TableComponent {
.takeUntil(this.ngUnsubscribe)
.subscribe(
(returnedUsers) => {
this.entries = returnedUsers;

this.entriesVault = returnedUsers;
this.entriesVault = this.removeDuplicateUsers(this.entriesVault);
this.paginateUsers(this.paginationData.currentPage);
},
error => {
console.error(error);
Expand All @@ -93,9 +152,7 @@ export class PermissionsTableRowsComponent implements OnInit, TableComponent {
},
() => { // onCompleted
this.openSnackBar(`User added to ${this.currentProject.name}`, 'close')

})
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
<div class="spinner-new rotating"></div>
</div>
<app-table-template
*ngIf="tableParams.totalListItems > 0"
*ngIf="!loading && tableParams.totalListItems !== 0"
[columns]="tableColumns"
[data]="tableData">
[data]="tableData"
(onPageNumUpdate)="handlePageChange($event)">
</app-table-template>
<div *ngIf="tableParams.totalListItems == 0">
<div *ngIf="tableParams.totalListItems === 0">
No users found.
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { get } from 'lodash';
Expand All @@ -20,6 +20,7 @@ import { PageBreadcrumb } from 'app/shared/components/navbar/types';
export class ProjectPermissionsComponent implements OnInit {

public users: User[] = null;
public userVault: User[] = null;
public currentProject: Project;
public loading = true;
public pageBreadcrumbs: PageBreadcrumb[];
Expand All @@ -42,6 +43,7 @@ export class ProjectPermissionsComponent implements OnInit {
];

constructor(
private _changeDetectionRef: ChangeDetectorRef,
private userService: UserService,
private route: ActivatedRoute,
private storageService: StorageService,
Expand All @@ -67,30 +69,61 @@ export class ProjectPermissionsComponent implements OnInit {
.subscribe(params => {
this.tableParams = this.tableTemplateUtils.getParamsFromUrl(params);
});
this.getUsers();
}

/**
* Retrieve the user list, with permissions info, from the user service
*
* @return {void}
*/
getUsers(): void {
this.userService.getAll()
.toPromise()
.then((user: User) => {
this.users = get(user, 'data');
this.tableParams.totalListItems = get(user, 'totalCount');
//return user;
this.setRowData();
this.loading = false;
this.userVault = get(user, 'data');
this.removeDuplicateUsers();
this.tableParams.totalListItems = this.userVault.length || 0;
this.paginateUsers(this.tableParams.currentPage);
})
.catch(error => {
console.error(error);
});
}

/**
* Remove users that have duplicate names, favouring entries that have permissions.
*
* @return {void}
*/
removeDuplicateUsers(): void {
let userNames = [];
let validatedUsers = [];
if (Array.isArray(this.userVault)) {
this.userVault.forEach(user => {
if (!userNames.includes(user.displayName)) {
// If no duplicate name is found, validate the user
userNames.push(user.displayName);
validatedUsers.push(user);
} else if (user.projectPermissions?.includes(this.currentProject._id)) {
// If a duplicate user is found and they have project permission, replace matching entry if it doesn't have permissions
const matchingUserIndex = validatedUsers.findIndex((usr) => usr.displayName === user.displayName);
validatedUsers[matchingUserIndex] = validatedUsers[matchingUserIndex].projectPermissions.includes(this.currentProject._id) ? validatedUsers[matchingUserIndex] : user;
}
})
}
this.userVault = validatedUsers;
}

/**
* Set the data to use in the table UI component. This displays
* the loaded users(with permissions) to the user.
*
* @return {void}
*/
setRowData() {
setRowData(): void {
let list = [];
if (this.users && this.users.length > 0) {
if (this.users?.length > 0) {
this.users.forEach(user => {
list.push(
{
Expand All @@ -108,4 +141,33 @@ export class ProjectPermissionsComponent implements OnInit {
}
}

/**
* Load a "page" of documents.
*
* @param {number} pageNumber The page number of documents to get.
* @return {void}
*/
public paginateUsers(pageNumber: number): void {
window.scrollTo(0, 0);
this.loading = true;
this.tableParams.currentPage = pageNumber;
const startIndex = (pageNumber - 1) * this.tableParams.pageSize;
const endIndex = startIndex + this.tableParams.pageSize;
if (endIndex && 0 < this.userVault.length) {
this.users = this.userVault.slice(startIndex, endIndex);
this.tableTemplateUtils.updateUrl(this.tableParams.sortBy, this.tableParams.currentPage, this.tableParams.pageSize, this.tableParams.filter, this.tableParams.keywords || '');
this.setRowData();
this.loading = false;
this._changeDetectionRef.detectChanges();
}
}

/**
* Handle a page change
*
*/
public handlePageChange(event: number): void {
this.tableParams.currentPage = event;
this.getUsers();
}
}

0 comments on commit 9d5997d

Please sign in to comment.